@xfey/tutti 0.1.33 → 0.1.35
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/README.md +3 -3
- package/dist/server-shell/cli/args.d.ts +6 -0
- package/dist/server-shell/cli/args.js +30 -0
- package/dist/server-shell/cli/cli.js +118 -6
- package/dist/server-shell/cli/errors.d.ts +1 -1
- package/dist/server-shell/cli/host-runtime-endpoint.d.ts +1 -0
- package/dist/server-shell/cli/host-runtime-endpoint.js +10 -5
- package/dist/server-shell/cli/launch.js +1 -0
- package/dist/server-shell/cli/machine-local.d.ts +3 -0
- package/dist/server-shell/cli/machine-local.js +24 -3
- package/dist/server-shell/cli/machine-project-inspector.d.ts +1 -0
- package/dist/server-shell/cli/machine-project-inspector.js +1 -0
- package/dist/server-shell/cli/managed-host.d.ts +1 -0
- package/dist/server-shell/cli/managed-host.js +6 -4
- package/dist/server-shell/cli/runtime-commands.d.ts +3 -2
- package/dist/server-shell/cli/runtime-commands.js +9 -1
- package/dist/server-shell/local-console/folder-picker.d.ts +0 -1
- package/dist/server-shell/local-console/folder-picker.js +2 -33
- package/dist/server-shell/local-console/invocation-context.d.ts +21 -0
- package/dist/server-shell/local-console/invocation-context.js +56 -0
- package/dist/server-shell/local-console/lifecycle-lock.d.ts +13 -0
- package/dist/server-shell/local-console/lifecycle-lock.js +135 -0
- package/dist/server-shell/local-console/managed-console.d.ts +38 -0
- package/dist/server-shell/local-console/managed-console.js +254 -36
- package/dist/server-shell/local-console/project-service.d.ts +16 -9
- package/dist/server-shell/local-console/project-service.js +152 -58
- package/dist/server-shell/local-console/runtime-endpoint.d.ts +15 -1
- package/dist/server-shell/local-console/runtime-endpoint.js +21 -5
- package/dist/server-shell/local-console/server.d.ts +12 -0
- package/dist/server-shell/local-console/server.js +152 -45
- package/dist/server-shell/local-console/session.d.ts +10 -15
- package/dist/server-shell/local-console/session.js +69 -17
- package/package.json +1 -1
- package/web/assets/index-DPuaTngs.js +29 -0
- package/web/assets/{index-BcZpeSaX.css → index-Dmbchapb.css} +1 -1
- package/web/index.html +2 -2
- package/web/assets/index-DKf4jz_E.js +0 -29
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { relayProjectRouteSegment } from "@tutti/shared/ids";
|
|
4
|
+
import { configureProjectOpenAiProvider, discoverOpenAiModels, readOpenAiProviderConfigProjection, } from "../../providers/openai/index.js";
|
|
4
5
|
import { formatCliErrorReason, LaunchError } from "../cli/errors.js";
|
|
5
|
-
import { prepareLaunchProject } from "../cli/launch.js";
|
|
6
|
+
import { prepareLaunchProject, resolveRelayUrl } from "../cli/launch.js";
|
|
6
7
|
import { rotateHostLocalInvite } from "../cli/local-control-client.js";
|
|
8
|
+
import { readHostRegistrationSecret, readMachineProjectBinding, readMachineRuntimeEndpoint, } from "../cli/machine-local.js";
|
|
7
9
|
import { spawnDetachedHost, waitForManagedHostReady } from "../cli/managed-host.js";
|
|
8
10
|
import { resolveManagedProjectContext } from "../cli/project-resolver.js";
|
|
9
11
|
import { listRuntimeProjects, runStopCommand, } from "../cli/runtime-commands.js";
|
|
12
|
+
import { readCliVersion } from "../cli/version.js";
|
|
13
|
+
import { createLocalConsoleOperationEnvironment, } from "./invocation-context.js";
|
|
10
14
|
export class LocalConsoleProjectError extends Error {
|
|
11
15
|
code;
|
|
12
16
|
statusCode;
|
|
@@ -44,7 +48,9 @@ function validateProvider(input) {
|
|
|
44
48
|
}
|
|
45
49
|
return provider;
|
|
46
50
|
}
|
|
47
|
-
function projectFromRuntimeRow(row, providerStatus) {
|
|
51
|
+
function projectFromRuntimeRow(row, providerStatus, metadata) {
|
|
52
|
+
const currentVersion = readCliVersion();
|
|
53
|
+
const openUrl = projectOpenUrl(metadata.relayUrl, row.relay_project_ref);
|
|
48
54
|
return {
|
|
49
55
|
project_id: row.project_id,
|
|
50
56
|
display_name: row.display_name,
|
|
@@ -53,32 +59,118 @@ function projectFromRuntimeRow(row, providerStatus) {
|
|
|
53
59
|
provider_status: providerStatus,
|
|
54
60
|
...(row.relay_project_ref === undefined ? {} : { relay_project_ref: row.relay_project_ref }),
|
|
55
61
|
...(row.join_url === undefined ? {} : { join_url: row.join_url }),
|
|
62
|
+
...(openUrl === undefined ? {} : { open_url: openUrl }),
|
|
56
63
|
...(row.relay_connection_status === undefined
|
|
57
64
|
? {}
|
|
58
65
|
: { relay_connection_status: row.relay_connection_status }),
|
|
66
|
+
...(metadata.activityAt === undefined ? {} : { activity_at: metadata.activityAt }),
|
|
67
|
+
...(metadata.createdAt === undefined ? {} : { created_at: metadata.createdAt }),
|
|
68
|
+
...(row.host_version === undefined ? {} : { host_version: row.host_version }),
|
|
69
|
+
...(row.host_version === undefined || row.host_version === currentVersion
|
|
70
|
+
? {}
|
|
71
|
+
: { update_required: true }),
|
|
59
72
|
};
|
|
60
73
|
}
|
|
74
|
+
function projectOpenUrl(relayUrl, relayProjectRef) {
|
|
75
|
+
if (relayUrl === undefined || relayProjectRef === undefined) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const url = new URL(`/projects?open=${encodeURIComponent(relayProjectRouteSegment(relayProjectRef))}`, relayUrl);
|
|
80
|
+
return url.protocol === "http:" || url.protocol === "https:" ? url.toString() : undefined;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function readProjectActivityAt(tuttiHome, row, binding) {
|
|
87
|
+
if (row.last_connected_at !== undefined) {
|
|
88
|
+
return row.last_connected_at;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const endpoint = readMachineRuntimeEndpoint(tuttiHome, row.project_id);
|
|
92
|
+
if (endpoint !== null) {
|
|
93
|
+
return endpoint.updated_at;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Invalid endpoint state is already represented by the project status.
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
return binding?.updated_at;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function relayUrlFromJoinUrl(joinUrl) {
|
|
107
|
+
if (joinUrl === undefined) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
return new URL(joinUrl).origin;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
61
117
|
export class LocalConsoleProjectService {
|
|
62
|
-
#
|
|
63
|
-
#
|
|
118
|
+
#tuttiHome;
|
|
119
|
+
#serviceEnvironment;
|
|
64
120
|
#launches = new Map();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.#
|
|
121
|
+
#mutationTail = Promise.resolve();
|
|
122
|
+
constructor(options) {
|
|
123
|
+
this.#tuttiHome = resolve(options.tuttiHome);
|
|
124
|
+
this.#serviceEnvironment = options.serviceEnvironment ?? process.env;
|
|
68
125
|
}
|
|
69
|
-
|
|
70
|
-
|
|
126
|
+
#operationOptions(context) {
|
|
127
|
+
return {
|
|
128
|
+
cwd: context.currentDirectory,
|
|
129
|
+
env: createLocalConsoleOperationEnvironment({
|
|
130
|
+
serviceEnvironment: this.#serviceEnvironment,
|
|
131
|
+
invocationEnvironment: context.environment,
|
|
132
|
+
tuttiHome: this.#tuttiHome,
|
|
133
|
+
}),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
#runMutation(operation) {
|
|
137
|
+
const result = this.#mutationTail.then(operation, operation);
|
|
138
|
+
this.#mutationTail = result.then(() => undefined, () => undefined);
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
async listProjects(context) {
|
|
142
|
+
const operation = this.#operationOptions(context);
|
|
71
143
|
const rows = await listRuntimeProjects({
|
|
72
144
|
all: true,
|
|
73
|
-
|
|
74
|
-
env: this.#env,
|
|
145
|
+
...operation,
|
|
75
146
|
});
|
|
76
147
|
return rows.map((row) => {
|
|
148
|
+
let binding = null;
|
|
149
|
+
try {
|
|
150
|
+
binding = readMachineProjectBinding(this.#tuttiHome, row.project_id);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Invalid binding state is already represented by the project status.
|
|
154
|
+
}
|
|
155
|
+
let createdAt = binding?.created_at;
|
|
156
|
+
if (createdAt === undefined) {
|
|
157
|
+
try {
|
|
158
|
+
createdAt = readHostRegistrationSecret(this.#tuttiHome, row.project_id).created_at;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Damaged legacy metadata remains visible without an invented creation date.
|
|
162
|
+
}
|
|
163
|
+
}
|
|
77
164
|
const provider = readOpenAiProviderConfigProjection({
|
|
78
|
-
tuttiHome,
|
|
165
|
+
tuttiHome: this.#tuttiHome,
|
|
79
166
|
projectId: row.project_id,
|
|
80
167
|
});
|
|
81
|
-
|
|
168
|
+
const activityAt = readProjectActivityAt(this.#tuttiHome, row, binding);
|
|
169
|
+
return projectFromRuntimeRow(row, provider.status, {
|
|
170
|
+
...(activityAt === undefined ? {} : { activityAt }),
|
|
171
|
+
...(createdAt === undefined ? {} : { createdAt }),
|
|
172
|
+
relayUrl: binding?.relay_url ?? relayUrlFromJoinUrl(row.join_url) ?? resolveRelayUrl(operation.env),
|
|
173
|
+
});
|
|
82
174
|
});
|
|
83
175
|
}
|
|
84
176
|
async discoverModels(input) {
|
|
@@ -92,29 +184,29 @@ export class LocalConsoleProjectService {
|
|
|
92
184
|
apiKey: provider.api_key,
|
|
93
185
|
});
|
|
94
186
|
}
|
|
95
|
-
async launchProject(input) {
|
|
187
|
+
async launchProject(input, context) {
|
|
96
188
|
const workspacePath = validateWorkspacePath(input.workspacePath);
|
|
97
189
|
const active = this.#launches.get(workspacePath);
|
|
98
190
|
if (active !== undefined) {
|
|
99
191
|
return await active;
|
|
100
192
|
}
|
|
101
|
-
const launch = this.#launchProject({
|
|
193
|
+
const launch = this.#runMutation(async () => await this.#launchProject({
|
|
102
194
|
workspacePath,
|
|
103
195
|
...(input.provider === undefined ? {} : { provider: validateProvider(input.provider) }),
|
|
104
|
-
}).finally(() => {
|
|
196
|
+
}, context)).finally(() => {
|
|
105
197
|
this.#launches.delete(workspacePath);
|
|
106
198
|
});
|
|
107
199
|
this.#launches.set(workspacePath, launch);
|
|
108
200
|
return await launch;
|
|
109
201
|
}
|
|
110
|
-
async #launchProject(input) {
|
|
202
|
+
async #launchProject(input, context) {
|
|
203
|
+
const operation = this.#operationOptions(context);
|
|
111
204
|
let preparation;
|
|
112
205
|
try {
|
|
113
206
|
preparation = await prepareLaunchProject({
|
|
114
207
|
workspacePath: input.workspacePath,
|
|
115
208
|
yes: true,
|
|
116
|
-
|
|
117
|
-
env: this.#env,
|
|
209
|
+
...operation,
|
|
118
210
|
});
|
|
119
211
|
}
|
|
120
212
|
catch (error) {
|
|
@@ -138,7 +230,8 @@ export class LocalConsoleProjectService {
|
|
|
138
230
|
try {
|
|
139
231
|
spawnDetachedHost({
|
|
140
232
|
workspaceRoot: preparation.workspace_root,
|
|
141
|
-
env:
|
|
233
|
+
env: operation.env,
|
|
234
|
+
inheritProcessEnv: false,
|
|
142
235
|
});
|
|
143
236
|
const ready = await waitForManagedHostReady({
|
|
144
237
|
tuttiHome: preparation.tutti_home,
|
|
@@ -148,13 +241,14 @@ export class LocalConsoleProjectService {
|
|
|
148
241
|
if (ready.join_url === undefined) {
|
|
149
242
|
throw new LocalConsoleProjectError("relay_registration_failed", "The host started, but Relay did not return a visible join link.");
|
|
150
243
|
}
|
|
151
|
-
const projects = await this.listProjects();
|
|
244
|
+
const projects = await this.listProjects(context);
|
|
152
245
|
const project = projects.find((item) => item.project_id === preparation.project_id);
|
|
153
246
|
if (project === undefined) {
|
|
154
247
|
throw new LocalConsoleProjectError("project_not_found", "The launched project could not be read from the machine project list.");
|
|
155
248
|
}
|
|
156
249
|
return {
|
|
157
250
|
project,
|
|
251
|
+
project_created: preparation.project_identity_created,
|
|
158
252
|
join_url: ready.join_url,
|
|
159
253
|
...(ready.join_token_expires_at === undefined
|
|
160
254
|
? {}
|
|
@@ -165,44 +259,44 @@ export class LocalConsoleProjectService {
|
|
|
165
259
|
throw this.#normalizeError(error);
|
|
166
260
|
}
|
|
167
261
|
}
|
|
168
|
-
async refreshInvite(projectId) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
try {
|
|
178
|
-
const status = await rotateHostLocalInvite({ endpoint: project.runtime_endpoint });
|
|
179
|
-
const joinUrl = status.relay?.join_url;
|
|
180
|
-
if (joinUrl === undefined) {
|
|
181
|
-
throw new LocalConsoleProjectError("relay_registration_failed", "Relay did not return a visible invite link.");
|
|
262
|
+
async refreshInvite(projectId, context) {
|
|
263
|
+
return await this.#runMutation(async () => {
|
|
264
|
+
const project = resolveManagedProjectContext({
|
|
265
|
+
target: projectId,
|
|
266
|
+
...this.#operationOptions(context),
|
|
267
|
+
});
|
|
268
|
+
if (project.runtime_endpoint === null) {
|
|
269
|
+
throw new LocalConsoleProjectError("host_not_running", "Launch this project before creating an invite link.");
|
|
182
270
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
271
|
+
try {
|
|
272
|
+
const status = await rotateHostLocalInvite({ endpoint: project.runtime_endpoint });
|
|
273
|
+
const joinUrl = status.relay?.join_url;
|
|
274
|
+
if (joinUrl === undefined) {
|
|
275
|
+
throw new LocalConsoleProjectError("relay_registration_failed", "Relay did not return a visible invite link.");
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
join_url: joinUrl,
|
|
279
|
+
...(status.relay?.join_token_expires_at === undefined
|
|
280
|
+
? {}
|
|
281
|
+
: { expires_at: status.relay.join_token_expires_at }),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
throw this.#normalizeError(error);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
193
288
|
}
|
|
194
|
-
async stopProject(projectId) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
289
|
+
async stopProject(projectId, context) {
|
|
290
|
+
return await this.#runMutation(async () => {
|
|
291
|
+
try {
|
|
292
|
+
return {
|
|
293
|
+
message: await runStopCommand(projectId, this.#operationOptions(context)),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
throw this.#normalizeError(error);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
206
300
|
}
|
|
207
301
|
#normalizeError(error) {
|
|
208
302
|
if (error instanceof LocalConsoleProjectError) {
|
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
export type LocalConsoleRuntimeEndpoint = {
|
|
2
|
+
schema_version: 2;
|
|
3
|
+
instance_id: string;
|
|
4
|
+
pid: number;
|
|
5
|
+
base_url: string;
|
|
6
|
+
control_token: string;
|
|
7
|
+
version: string;
|
|
8
|
+
entrypoint: string;
|
|
9
|
+
started_at: string;
|
|
10
|
+
};
|
|
11
|
+
export type LegacyLocalConsoleRuntimeEndpoint = {
|
|
2
12
|
schema_version: 1;
|
|
3
13
|
pid: number;
|
|
4
14
|
base_url: string;
|
|
5
15
|
control_token: string;
|
|
6
16
|
started_at: string;
|
|
7
17
|
};
|
|
18
|
+
export type ReadableLocalConsoleRuntimeEndpoint = LocalConsoleRuntimeEndpoint | LegacyLocalConsoleRuntimeEndpoint;
|
|
8
19
|
export declare function createLocalConsoleSecret(): string;
|
|
9
|
-
export declare function readLocalConsoleRuntimeEndpoint(tuttiHome: string):
|
|
20
|
+
export declare function readLocalConsoleRuntimeEndpoint(tuttiHome: string): ReadableLocalConsoleRuntimeEndpoint | null;
|
|
10
21
|
export declare function writeLocalConsoleRuntimeEndpoint(options: {
|
|
11
22
|
tuttiHome: string;
|
|
23
|
+
instanceId: string;
|
|
12
24
|
pid: number;
|
|
13
25
|
baseUrl: string;
|
|
14
26
|
controlToken: string;
|
|
27
|
+
version: string;
|
|
28
|
+
entrypoint: string;
|
|
15
29
|
now?: () => Date;
|
|
16
30
|
}): LocalConsoleRuntimeEndpoint;
|
|
17
31
|
export declare function deleteLocalConsoleRuntimeEndpoint(options: {
|
|
@@ -7,10 +7,8 @@ function endpointPath(tuttiHome) {
|
|
|
7
7
|
function isRecord(value) {
|
|
8
8
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
return (
|
|
12
|
-
value.schema_version === 1 &&
|
|
13
|
-
typeof value.pid === "number" &&
|
|
10
|
+
function hasSharedEndpointFields(value) {
|
|
11
|
+
return (typeof value.pid === "number" &&
|
|
14
12
|
Number.isInteger(value.pid) &&
|
|
15
13
|
typeof value.base_url === "string" &&
|
|
16
14
|
/^http:\/\/127\.0\.0\.1:\d+$/u.test(value.base_url) &&
|
|
@@ -18,6 +16,21 @@ function isEndpoint(value) {
|
|
|
18
16
|
value.control_token.length >= 32 &&
|
|
19
17
|
typeof value.started_at === "string");
|
|
20
18
|
}
|
|
19
|
+
function isEndpoint(value) {
|
|
20
|
+
if (!isRecord(value) || !hasSharedEndpointFields(value)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (value.schema_version === 1) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return (value.schema_version === 2 &&
|
|
27
|
+
typeof value.instance_id === "string" &&
|
|
28
|
+
value.instance_id.length >= 16 &&
|
|
29
|
+
typeof value.version === "string" &&
|
|
30
|
+
value.version.trim() !== "" &&
|
|
31
|
+
typeof value.entrypoint === "string" &&
|
|
32
|
+
value.entrypoint.trim() !== "");
|
|
33
|
+
}
|
|
21
34
|
export function createLocalConsoleSecret() {
|
|
22
35
|
return randomBytes(32).toString("base64url");
|
|
23
36
|
}
|
|
@@ -36,10 +49,13 @@ export function readLocalConsoleRuntimeEndpoint(tuttiHome) {
|
|
|
36
49
|
}
|
|
37
50
|
export function writeLocalConsoleRuntimeEndpoint(options) {
|
|
38
51
|
const record = {
|
|
39
|
-
schema_version:
|
|
52
|
+
schema_version: 2,
|
|
53
|
+
instance_id: options.instanceId,
|
|
40
54
|
pid: options.pid,
|
|
41
55
|
base_url: options.baseUrl,
|
|
42
56
|
control_token: options.controlToken,
|
|
57
|
+
version: options.version,
|
|
58
|
+
entrypoint: options.entrypoint,
|
|
43
59
|
started_at: (options.now ?? (() => new Date()))().toISOString(),
|
|
44
60
|
};
|
|
45
61
|
if (!isEndpoint(record)) {
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { type FastifyInstance } from "fastify";
|
|
2
2
|
export declare const LOCAL_CONSOLE_API_BASE = "/local-console/v1";
|
|
3
|
+
type LocalConsoleRuntimeMetadata = {
|
|
4
|
+
instanceId: string;
|
|
5
|
+
version: string;
|
|
6
|
+
entrypoint: string;
|
|
7
|
+
startedAt: string;
|
|
8
|
+
pid: number;
|
|
9
|
+
};
|
|
3
10
|
type LocalConsoleServerOptions = {
|
|
4
11
|
controlToken: string;
|
|
5
12
|
cwd: string;
|
|
13
|
+
tuttiHome?: string;
|
|
6
14
|
env?: NodeJS.ProcessEnv;
|
|
7
15
|
now?: () => Date;
|
|
8
16
|
webStaticRoot?: string | false;
|
|
17
|
+
runtime?: LocalConsoleRuntimeMetadata;
|
|
18
|
+
onActivity?: () => void;
|
|
19
|
+
onShutdown?: () => void;
|
|
9
20
|
};
|
|
10
21
|
export declare function createLocalConsoleServer(options: LocalConsoleServerOptions): FastifyInstance;
|
|
11
22
|
export declare function runLocalConsoleProcess(options?: {
|
|
12
23
|
cwd?: string;
|
|
13
24
|
env?: NodeJS.ProcessEnv;
|
|
14
25
|
now?: () => Date;
|
|
26
|
+
idleTimeoutMs?: number;
|
|
15
27
|
}): Promise<void>;
|
|
16
28
|
export {};
|
|
17
29
|
//# sourceMappingURL=server.d.ts.map
|