codex-blocker 0.0.6 → 0.0.8
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 +2 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-FXDFFIXM.js → chunk-2Q6Z6NQH.js} +161 -76
- package/dist/server.d.ts +53 -2
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,7 +39,8 @@ npx codex-blocker --help
|
|
|
39
39
|
## How It Works
|
|
40
40
|
|
|
41
41
|
1. **Codex sessions** — The server tails Codex session logs under `~/.codex/sessions`
|
|
42
|
-
to detect activity.
|
|
42
|
+
to detect activity. It marks a session “working” on your prompt and “idle” on the
|
|
43
|
+
final assistant reply (tool calls don’t count as idle).
|
|
43
44
|
|
|
44
45
|
2. **Server** — Runs on localhost and:
|
|
45
46
|
- Tracks active Codex sessions
|
package/dist/bin.js
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
import { createServer } from "http";
|
|
3
3
|
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
4
|
import { homedir as homedir2 } from "os";
|
|
5
|
-
import { join as join2 } from "path";
|
|
5
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
6
6
|
import { WebSocketServer, WebSocket } from "ws";
|
|
7
7
|
|
|
8
8
|
// src/types.ts
|
|
9
9
|
var DEFAULT_PORT = 8765;
|
|
10
10
|
var SESSION_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
11
|
-
var CODEX_ACTIVITY_IDLE_TIMEOUT_MS = 60 * 1e3;
|
|
12
11
|
var CODEX_SESSIONS_SCAN_INTERVAL_MS = 2e3;
|
|
13
12
|
|
|
14
13
|
// src/state.ts
|
|
@@ -142,9 +141,10 @@ var state = new SessionState();
|
|
|
142
141
|
// src/codex.ts
|
|
143
142
|
import { existsSync, createReadStream, promises as fs } from "fs";
|
|
144
143
|
import { homedir } from "os";
|
|
145
|
-
import {
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
import { join } from "path";
|
|
145
|
+
|
|
146
|
+
// src/codex-parse.ts
|
|
147
|
+
import { basename, dirname } from "path";
|
|
148
148
|
function isRolloutFile(filePath) {
|
|
149
149
|
const name = basename(filePath);
|
|
150
150
|
return name === "rollout.jsonl" || /^rollout-.+\.jsonl$/.test(name);
|
|
@@ -183,6 +183,47 @@ function findFirstStringValue(obj, keys, maxDepth = 6) {
|
|
|
183
183
|
}
|
|
184
184
|
return void 0;
|
|
185
185
|
}
|
|
186
|
+
function parseCodexLine(line, sessionId) {
|
|
187
|
+
let currentSessionId = sessionId;
|
|
188
|
+
let previousSessionId;
|
|
189
|
+
let cwd;
|
|
190
|
+
let markWorking = false;
|
|
191
|
+
let markIdle = false;
|
|
192
|
+
try {
|
|
193
|
+
const payload = JSON.parse(line);
|
|
194
|
+
const entryType = typeof payload.type === "string" ? payload.type : void 0;
|
|
195
|
+
const innerPayload = payload.payload;
|
|
196
|
+
const innerType = innerPayload && typeof innerPayload === "object" ? innerPayload.type : void 0;
|
|
197
|
+
if (entryType === "session_meta") {
|
|
198
|
+
const metaId = innerPayload && typeof innerPayload === "object" ? innerPayload.id : void 0;
|
|
199
|
+
if (typeof metaId === "string" && metaId.length > 0 && metaId !== currentSessionId) {
|
|
200
|
+
previousSessionId = currentSessionId;
|
|
201
|
+
currentSessionId = metaId;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
cwd = findFirstStringValue(innerPayload, ["cwd"]) ?? findFirstStringValue(payload, ["cwd"]);
|
|
205
|
+
const innerTypeString = typeof innerType === "string" ? innerType : void 0;
|
|
206
|
+
if (entryType === "event_msg" && innerTypeString === "user_message") {
|
|
207
|
+
markWorking = true;
|
|
208
|
+
}
|
|
209
|
+
if (entryType === "event_msg" && innerTypeString === "agent_message") {
|
|
210
|
+
markIdle = true;
|
|
211
|
+
}
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
sessionId: currentSessionId,
|
|
216
|
+
previousSessionId,
|
|
217
|
+
cwd,
|
|
218
|
+
markWorking,
|
|
219
|
+
markIdle
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/codex.ts
|
|
224
|
+
var DEFAULT_CODEX_HOME = join(homedir(), ".codex");
|
|
225
|
+
var TAIL_MAX_BYTES = 64 * 1024;
|
|
226
|
+
var TAIL_MAX_LINES = 200;
|
|
186
227
|
async function listRolloutFiles(root) {
|
|
187
228
|
const files = [];
|
|
188
229
|
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
@@ -196,6 +237,30 @@ async function listRolloutFiles(root) {
|
|
|
196
237
|
}
|
|
197
238
|
return files;
|
|
198
239
|
}
|
|
240
|
+
async function readTailLines(filePath, fileSize, maxBytes, maxLines) {
|
|
241
|
+
if (fileSize === 0) return [];
|
|
242
|
+
const start = Math.max(0, fileSize - maxBytes);
|
|
243
|
+
const end = Math.max(fileSize - 1, start);
|
|
244
|
+
const chunks = [];
|
|
245
|
+
await new Promise((resolve, reject) => {
|
|
246
|
+
const stream = createReadStream(filePath, { start, end });
|
|
247
|
+
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
248
|
+
stream.on("error", reject);
|
|
249
|
+
stream.on("end", resolve);
|
|
250
|
+
});
|
|
251
|
+
let content = Buffer.concat(chunks).toString("utf-8");
|
|
252
|
+
let lines = content.split("\n");
|
|
253
|
+
if (start > 0 && content[0] !== "\n") {
|
|
254
|
+
lines = lines.slice(1);
|
|
255
|
+
}
|
|
256
|
+
if (lines.length > 0 && lines[lines.length - 1]?.trim() === "") {
|
|
257
|
+
lines.pop();
|
|
258
|
+
}
|
|
259
|
+
if (lines.length > maxLines) {
|
|
260
|
+
lines = lines.slice(-maxLines);
|
|
261
|
+
}
|
|
262
|
+
return lines.filter((line) => line.trim().length > 0);
|
|
263
|
+
}
|
|
199
264
|
async function readNewLines(filePath, fileState) {
|
|
200
265
|
const stat = await fs.stat(filePath);
|
|
201
266
|
if (stat.size < fileState.position) {
|
|
@@ -218,51 +283,17 @@ async function readNewLines(filePath, fileState) {
|
|
|
218
283
|
fileState.remainder = content.endsWith("\n") ? "" : lines.pop() ?? "";
|
|
219
284
|
return lines.filter((line) => line.trim().length > 0);
|
|
220
285
|
}
|
|
221
|
-
function handleLine(line, fileState) {
|
|
222
|
-
let sessionId = fileState.sessionId;
|
|
223
|
-
let cwd;
|
|
224
|
-
let shouldMarkWorking = false;
|
|
225
|
-
let shouldMarkIdle = false;
|
|
226
|
-
try {
|
|
227
|
-
const payload = JSON.parse(line);
|
|
228
|
-
const entryType = typeof payload.type === "string" ? payload.type : void 0;
|
|
229
|
-
const innerPayload = payload.payload;
|
|
230
|
-
const innerType = innerPayload && typeof innerPayload === "object" ? innerPayload.type : void 0;
|
|
231
|
-
if (entryType === "session_meta") {
|
|
232
|
-
const metaId = innerPayload && typeof innerPayload === "object" ? innerPayload.id : void 0;
|
|
233
|
-
if (typeof metaId === "string" && metaId.length > 0 && metaId !== sessionId) {
|
|
234
|
-
const previousId = sessionId;
|
|
235
|
-
fileState.sessionId = metaId;
|
|
236
|
-
sessionId = metaId;
|
|
237
|
-
state.removeSession(previousId);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
cwd = findFirstStringValue(innerPayload, ["cwd"]) ?? findFirstStringValue(payload, ["cwd"]);
|
|
241
|
-
const innerTypeString = typeof innerType === "string" ? innerType : void 0;
|
|
242
|
-
if (entryType === "event_msg" && innerTypeString === "user_message") {
|
|
243
|
-
shouldMarkWorking = true;
|
|
244
|
-
}
|
|
245
|
-
if (entryType === "event_msg" && innerTypeString === "agent_message") {
|
|
246
|
-
shouldMarkIdle = true;
|
|
247
|
-
}
|
|
248
|
-
} catch {
|
|
249
|
-
}
|
|
250
|
-
state.markCodexSessionSeen(sessionId, cwd);
|
|
251
|
-
if (shouldMarkWorking) {
|
|
252
|
-
state.handleCodexActivity({
|
|
253
|
-
sessionId,
|
|
254
|
-
cwd,
|
|
255
|
-
idleTimeoutMs: CODEX_ACTIVITY_IDLE_TIMEOUT_MS
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
if (shouldMarkIdle) {
|
|
259
|
-
state.setCodexIdle(sessionId, cwd);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
286
|
var CodexSessionWatcher = class {
|
|
263
287
|
fileStates = /* @__PURE__ */ new Map();
|
|
264
288
|
scanTimer = null;
|
|
265
289
|
warnedMissing = false;
|
|
290
|
+
sessionsDir;
|
|
291
|
+
state;
|
|
292
|
+
constructor(state2, options) {
|
|
293
|
+
this.state = state2;
|
|
294
|
+
const base = process.env.CODEX_HOME ?? DEFAULT_CODEX_HOME;
|
|
295
|
+
this.sessionsDir = options?.sessionsDir ?? join(base, "sessions");
|
|
296
|
+
}
|
|
266
297
|
start() {
|
|
267
298
|
this.scan();
|
|
268
299
|
this.scanTimer = setInterval(() => {
|
|
@@ -276,9 +307,9 @@ var CodexSessionWatcher = class {
|
|
|
276
307
|
}
|
|
277
308
|
}
|
|
278
309
|
async scan() {
|
|
279
|
-
if (!existsSync(
|
|
310
|
+
if (!existsSync(this.sessionsDir)) {
|
|
280
311
|
if (!this.warnedMissing) {
|
|
281
|
-
console.log(`Waiting for Codex sessions at ${
|
|
312
|
+
console.log(`Waiting for Codex sessions at ${this.sessionsDir}`);
|
|
282
313
|
this.warnedMissing = true;
|
|
283
314
|
}
|
|
284
315
|
return;
|
|
@@ -286,7 +317,7 @@ var CodexSessionWatcher = class {
|
|
|
286
317
|
this.warnedMissing = false;
|
|
287
318
|
let files = [];
|
|
288
319
|
try {
|
|
289
|
-
files = await listRolloutFiles(
|
|
320
|
+
files = await listRolloutFiles(this.sessionsDir);
|
|
290
321
|
} catch {
|
|
291
322
|
return;
|
|
292
323
|
}
|
|
@@ -301,6 +332,15 @@ var CodexSessionWatcher = class {
|
|
|
301
332
|
try {
|
|
302
333
|
const stat = await fs.stat(filePath);
|
|
303
334
|
fileState.position = stat.size;
|
|
335
|
+
const tailLines = await readTailLines(
|
|
336
|
+
filePath,
|
|
337
|
+
stat.size,
|
|
338
|
+
TAIL_MAX_BYTES,
|
|
339
|
+
TAIL_MAX_LINES
|
|
340
|
+
);
|
|
341
|
+
if (tailLines.length > 0) {
|
|
342
|
+
this.processLines(tailLines, fileState);
|
|
343
|
+
}
|
|
304
344
|
} catch {
|
|
305
345
|
continue;
|
|
306
346
|
}
|
|
@@ -313,34 +353,52 @@ var CodexSessionWatcher = class {
|
|
|
313
353
|
continue;
|
|
314
354
|
}
|
|
315
355
|
if (newLines.length === 0) continue;
|
|
316
|
-
|
|
317
|
-
|
|
356
|
+
this.processLines(newLines, fileState);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
processLines(lines, fileState) {
|
|
360
|
+
for (const line of lines) {
|
|
361
|
+
const parsed = parseCodexLine(line, fileState.sessionId);
|
|
362
|
+
fileState.sessionId = parsed.sessionId;
|
|
363
|
+
if (parsed.previousSessionId) {
|
|
364
|
+
this.state.removeSession(parsed.previousSessionId);
|
|
365
|
+
}
|
|
366
|
+
this.state.markCodexSessionSeen(parsed.sessionId, parsed.cwd);
|
|
367
|
+
if (parsed.markWorking) {
|
|
368
|
+
this.state.handleCodexActivity({
|
|
369
|
+
sessionId: parsed.sessionId,
|
|
370
|
+
cwd: parsed.cwd
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
if (parsed.markIdle) {
|
|
374
|
+
this.state.setCodexIdle(parsed.sessionId, parsed.cwd);
|
|
318
375
|
}
|
|
319
376
|
}
|
|
320
377
|
}
|
|
321
378
|
};
|
|
322
379
|
|
|
323
380
|
// src/server.ts
|
|
324
|
-
var
|
|
325
|
-
var
|
|
381
|
+
var DEFAULT_TOKEN_DIR = join2(homedir2(), ".codex-blocker");
|
|
382
|
+
var DEFAULT_TOKEN_PATH = join2(DEFAULT_TOKEN_DIR, "token");
|
|
326
383
|
var RATE_WINDOW_MS = 6e4;
|
|
327
384
|
var RATE_LIMIT = 60;
|
|
328
385
|
var MAX_WS_CONNECTIONS_PER_IP = 3;
|
|
329
386
|
var rateByIp = /* @__PURE__ */ new Map();
|
|
330
387
|
var wsConnectionsByIp = /* @__PURE__ */ new Map();
|
|
331
|
-
function loadToken() {
|
|
332
|
-
if (!existsSync2(
|
|
388
|
+
function loadToken(tokenPath) {
|
|
389
|
+
if (!existsSync2(tokenPath)) return null;
|
|
333
390
|
try {
|
|
334
|
-
return readFileSync(
|
|
391
|
+
return readFileSync(tokenPath, "utf-8").trim() || null;
|
|
335
392
|
} catch {
|
|
336
393
|
return null;
|
|
337
394
|
}
|
|
338
395
|
}
|
|
339
|
-
function saveToken(token) {
|
|
340
|
-
|
|
341
|
-
|
|
396
|
+
function saveToken(tokenPath, token) {
|
|
397
|
+
const tokenDir = dirname2(tokenPath);
|
|
398
|
+
if (!existsSync2(tokenDir)) {
|
|
399
|
+
mkdirSync(tokenDir, { recursive: true });
|
|
342
400
|
}
|
|
343
|
-
writeFileSync(
|
|
401
|
+
writeFileSync(tokenPath, token, "utf-8");
|
|
344
402
|
}
|
|
345
403
|
function isChromeExtensionOrigin(origin) {
|
|
346
404
|
return Boolean(origin && origin.startsWith("chrome-extension://"));
|
|
@@ -374,8 +432,12 @@ function sendJson(res, data, status = 200) {
|
|
|
374
432
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
375
433
|
res.end(JSON.stringify(data));
|
|
376
434
|
}
|
|
377
|
-
function startServer(port = DEFAULT_PORT) {
|
|
378
|
-
|
|
435
|
+
function startServer(port = DEFAULT_PORT, options) {
|
|
436
|
+
const stateInstance = options?.state ?? state;
|
|
437
|
+
const tokenPath = options?.tokenPath ?? DEFAULT_TOKEN_PATH;
|
|
438
|
+
const startWatcher = options?.startWatcher ?? true;
|
|
439
|
+
const logBanner = options?.log ?? true;
|
|
440
|
+
let authToken = loadToken(tokenPath);
|
|
379
441
|
const server = createServer(async (req, res) => {
|
|
380
442
|
const clientIp = getClientIp(req);
|
|
381
443
|
if (!checkRateLimit(clientIp)) {
|
|
@@ -407,13 +469,13 @@ function startServer(port = DEFAULT_PORT) {
|
|
|
407
469
|
}
|
|
408
470
|
} else if (providedToken && allowOrigin) {
|
|
409
471
|
authToken = providedToken;
|
|
410
|
-
saveToken(providedToken);
|
|
472
|
+
saveToken(tokenPath, providedToken);
|
|
411
473
|
} else {
|
|
412
474
|
sendJson(res, { error: "Unauthorized" }, 401);
|
|
413
475
|
return;
|
|
414
476
|
}
|
|
415
477
|
if (req.method === "GET" && url.pathname === "/status") {
|
|
416
|
-
sendJson(res,
|
|
478
|
+
sendJson(res, stateInstance.getStatus());
|
|
417
479
|
return;
|
|
418
480
|
}
|
|
419
481
|
sendJson(res, { error: "Not found" }, 404);
|
|
@@ -437,13 +499,13 @@ function startServer(port = DEFAULT_PORT) {
|
|
|
437
499
|
}
|
|
438
500
|
} else if (providedToken && allowOrigin) {
|
|
439
501
|
authToken = providedToken;
|
|
440
|
-
saveToken(providedToken);
|
|
502
|
+
saveToken(tokenPath, providedToken);
|
|
441
503
|
} else {
|
|
442
504
|
ws.close(1008, "Unauthorized");
|
|
443
505
|
return;
|
|
444
506
|
}
|
|
445
507
|
wsConnectionsByIp.set(clientIp, currentConnections + 1);
|
|
446
|
-
const unsubscribe =
|
|
508
|
+
const unsubscribe = stateInstance.subscribe((message) => {
|
|
447
509
|
if (ws.readyState === WebSocket.OPEN) {
|
|
448
510
|
ws.send(JSON.stringify(message));
|
|
449
511
|
}
|
|
@@ -472,16 +534,40 @@ function startServer(port = DEFAULT_PORT) {
|
|
|
472
534
|
);
|
|
473
535
|
});
|
|
474
536
|
});
|
|
475
|
-
const codexWatcher = new CodexSessionWatcher(
|
|
476
|
-
|
|
537
|
+
const codexWatcher = new CodexSessionWatcher(stateInstance, {
|
|
538
|
+
sessionsDir: options?.sessionsDir
|
|
539
|
+
});
|
|
540
|
+
if (startWatcher) {
|
|
541
|
+
codexWatcher.start();
|
|
542
|
+
}
|
|
543
|
+
let resolveReady = () => {
|
|
544
|
+
};
|
|
545
|
+
const ready = new Promise((resolve) => {
|
|
546
|
+
resolveReady = resolve;
|
|
547
|
+
});
|
|
548
|
+
const handle = {
|
|
549
|
+
port,
|
|
550
|
+
ready,
|
|
551
|
+
close: async () => {
|
|
552
|
+
stateInstance.destroy();
|
|
553
|
+
codexWatcher.stop();
|
|
554
|
+
await new Promise((resolve) => wss.close(() => resolve()));
|
|
555
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
556
|
+
}
|
|
557
|
+
};
|
|
477
558
|
server.listen(port, "127.0.0.1", () => {
|
|
559
|
+
const address = server.address();
|
|
560
|
+
const actualPort = typeof address === "object" && address ? address.port : port;
|
|
561
|
+
handle.port = actualPort;
|
|
562
|
+
resolveReady(actualPort);
|
|
563
|
+
if (!logBanner) return;
|
|
478
564
|
console.log(`
|
|
479
565
|
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
480
566
|
\u2502 \u2502
|
|
481
567
|
\u2502 Codex Blocker Server \u2502
|
|
482
568
|
\u2502 \u2502
|
|
483
|
-
\u2502 HTTP: http://localhost:${
|
|
484
|
-
\u2502 WebSocket: ws://localhost:${
|
|
569
|
+
\u2502 HTTP: http://localhost:${actualPort} \u2502
|
|
570
|
+
\u2502 WebSocket: ws://localhost:${actualPort}/ws \u2502
|
|
485
571
|
\u2502 \u2502
|
|
486
572
|
\u2502 Watching Codex sessions... \u2502
|
|
487
573
|
\u2502 \u2502
|
|
@@ -489,13 +575,12 @@ function startServer(port = DEFAULT_PORT) {
|
|
|
489
575
|
`);
|
|
490
576
|
});
|
|
491
577
|
process.once("SIGINT", () => {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
server.close();
|
|
497
|
-
process.exit(0);
|
|
578
|
+
if (logBanner) {
|
|
579
|
+
console.log("\nShutting down...");
|
|
580
|
+
}
|
|
581
|
+
void handle.close().then(() => process.exit(0));
|
|
498
582
|
});
|
|
583
|
+
return handle;
|
|
499
584
|
}
|
|
500
585
|
|
|
501
586
|
export {
|
package/dist/server.d.ts
CHANGED
|
@@ -1,3 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
interface CodexActivity {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
cwd?: string;
|
|
4
|
+
idleTimeoutMs?: number;
|
|
5
|
+
}
|
|
6
|
+
type ServerMessage = {
|
|
7
|
+
type: "state";
|
|
8
|
+
blocked: boolean;
|
|
9
|
+
sessions: number;
|
|
10
|
+
working: number;
|
|
11
|
+
waitingForInput: number;
|
|
12
|
+
} | {
|
|
13
|
+
type: "pong";
|
|
14
|
+
};
|
|
2
15
|
|
|
3
|
-
|
|
16
|
+
type StateChangeCallback = (message: ServerMessage) => void;
|
|
17
|
+
declare class SessionState {
|
|
18
|
+
private sessions;
|
|
19
|
+
private listeners;
|
|
20
|
+
private cleanupInterval;
|
|
21
|
+
constructor();
|
|
22
|
+
subscribe(callback: StateChangeCallback): () => void;
|
|
23
|
+
private broadcast;
|
|
24
|
+
private getStateMessage;
|
|
25
|
+
handleCodexActivity(activity: CodexActivity): void;
|
|
26
|
+
setCodexIdle(sessionId: string, cwd?: string): void;
|
|
27
|
+
markCodexSessionSeen(sessionId: string, cwd?: string): void;
|
|
28
|
+
removeSession(sessionId: string): void;
|
|
29
|
+
private ensureSession;
|
|
30
|
+
private cleanupStaleSessions;
|
|
31
|
+
getStatus(): {
|
|
32
|
+
blocked: boolean;
|
|
33
|
+
sessions: number;
|
|
34
|
+
working: number;
|
|
35
|
+
waitingForInput: number;
|
|
36
|
+
};
|
|
37
|
+
destroy(): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type ServerOptions = {
|
|
41
|
+
sessionsDir?: string;
|
|
42
|
+
startWatcher?: boolean;
|
|
43
|
+
tokenPath?: string;
|
|
44
|
+
state?: SessionState;
|
|
45
|
+
log?: boolean;
|
|
46
|
+
};
|
|
47
|
+
type ServerHandle = {
|
|
48
|
+
port: number;
|
|
49
|
+
ready: Promise<number>;
|
|
50
|
+
close: () => Promise<void>;
|
|
51
|
+
};
|
|
52
|
+
declare function startServer(port?: number, options?: ServerOptions): ServerHandle;
|
|
53
|
+
|
|
54
|
+
export { type ServerHandle, type ServerOptions, startServer };
|
package/dist/server.js
CHANGED
package/package.json
CHANGED