@fnndsc/porter 0.2.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.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @file The one thing the door does with a password: trade it for a token.
3
+ *
4
+ * CUBE is the identity provider. The porter posts the operator's password to
5
+ * `auth-token/` once, keeps the token it gets back for the session it
6
+ * starts, and holds no password anywhere — not in memory past this call,
7
+ * not on disk, not on a child's argv.
8
+ *
9
+ * @module
10
+ */
11
+ /** What CUBE said to a login. */
12
+ export interface TokenMint {
13
+ /** The token, when CUBE issued one. */
14
+ token: string | null;
15
+ /** Why not, when it did not: CUBE's status, or the network's word. */
16
+ reason?: string;
17
+ }
18
+ /** The shape of `fetch` this module needs, so a test can stand one in. */
19
+ export type FetchLike = (url: string, init: {
20
+ method: string;
21
+ headers: Record<string, string>;
22
+ body: string;
23
+ }) => Promise<{
24
+ ok: boolean;
25
+ status: number;
26
+ json(): Promise<unknown>;
27
+ }>;
28
+ /**
29
+ * Trades a password for a CUBE token.
30
+ *
31
+ * @param cubeUrl - The CUBE API base, trailing slash included.
32
+ * @param username - The operator's CUBE username.
33
+ * @param password - The operator's password; used here and nowhere else.
34
+ * @param fetchLike - The HTTP client; the global `fetch` by default.
35
+ * @returns The token, or the reason there is none.
36
+ */
37
+ export declare function cubeToken_mint(cubeUrl: string, username: string, password: string, fetchLike?: FetchLike): Promise<TokenMint>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @file The one thing the door does with a password: trade it for a token.
3
+ *
4
+ * CUBE is the identity provider. The porter posts the operator's password to
5
+ * `auth-token/` once, keeps the token it gets back for the session it
6
+ * starts, and holds no password anywhere — not in memory past this call,
7
+ * not on disk, not on a child's argv.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * Trades a password for a CUBE token.
13
+ *
14
+ * @param cubeUrl - The CUBE API base, trailing slash included.
15
+ * @param username - The operator's CUBE username.
16
+ * @param password - The operator's password; used here and nowhere else.
17
+ * @param fetchLike - The HTTP client; the global `fetch` by default.
18
+ * @returns The token, or the reason there is none.
19
+ */
20
+ export async function cubeToken_mint(cubeUrl, username, password, fetchLike = fetch) {
21
+ let response;
22
+ try {
23
+ response = await fetchLike(`${cubeUrl}auth-token/`, {
24
+ method: 'POST',
25
+ headers: { 'Content-Type': 'application/json' },
26
+ body: JSON.stringify({ username, password }),
27
+ });
28
+ }
29
+ catch (error) {
30
+ return { token: null, reason: `CUBE unreachable: ${error instanceof Error ? error.message : String(error)}` };
31
+ }
32
+ if (!response.ok) {
33
+ return { token: null, reason: response.status === 400 || response.status === 401 ? 'CUBE refused the login' : `CUBE answered ${response.status}` };
34
+ }
35
+ const body = await response.json();
36
+ const token = typeof body === 'object' && body !== null ? body.token : undefined;
37
+ if (typeof token !== 'string' || token.length === 0) {
38
+ return { token: null, reason: 'CUBE answered without a token' };
39
+ }
40
+ return { token };
41
+ }
42
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/cube/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAaH;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAe,EACf,QAAgB,EAChB,QAAgB,EAChB,YAAuB,KAA6B;IAEpD,IAAI,QAAmE,CAAC;IACxE,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,OAAO,aAAa,EAAE;YAClD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;SAC7C,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;IAChH,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,iBAAiB,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACrJ,CAAC;IACD,MAAM,IAAI,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAY,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAE,IAA4B,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACnH,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,+BAA+B,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC"}
package/dist/door.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @file The door's cookie.
3
+ *
4
+ * The cookie names the session the browser was let into, signed so the
5
+ * browser cannot name another. HttpOnly, so a script in the page cannot read
6
+ * it; SameSite=Lax, so a link from elsewhere carries it but a form from
7
+ * elsewhere does not; Secure when the page came over TLS.
8
+ *
9
+ * @module
10
+ */
11
+ /** The cookie the door sets. */
12
+ export declare const DOOR_COOKIE: string;
13
+ /** The cookie's attributes for one deployment. */
14
+ export interface DoorCookieOptions {
15
+ path: string;
16
+ httpOnly: true;
17
+ sameSite: 'lax';
18
+ secure: boolean;
19
+ signed: true;
20
+ maxAge: number;
21
+ }
22
+ /**
23
+ * The attributes the door's cookie is set with.
24
+ *
25
+ * @param hours - How long the browser stays let in.
26
+ * @param secure - Whether the page came over TLS.
27
+ * @returns The cookie options.
28
+ */
29
+ export declare function doorCookie_options(hours: number, secure: boolean): DoorCookieOptions;
package/dist/door.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file The door's cookie.
3
+ *
4
+ * The cookie names the session the browser was let into, signed so the
5
+ * browser cannot name another. HttpOnly, so a script in the page cannot read
6
+ * it; SameSite=Lax, so a link from elsewhere carries it but a form from
7
+ * elsewhere does not; Secure when the page came over TLS.
8
+ *
9
+ * @module
10
+ */
11
+ /** The cookie the door sets. */
12
+ export const DOOR_COOKIE = 'porter_session';
13
+ /**
14
+ * The attributes the door's cookie is set with.
15
+ *
16
+ * @param hours - How long the browser stays let in.
17
+ * @param secure - Whether the page came over TLS.
18
+ * @returns The cookie options.
19
+ */
20
+ export function doorCookie_options(hours, secure) {
21
+ return { path: '/', httpOnly: true, sameSite: 'lax', secure, signed: true, maxAge: Math.round(hours * 3600) };
22
+ }
23
+ //# sourceMappingURL=door.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"door.js","sourceRoot":"","sources":["../src/door.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gCAAgC;AAChC,MAAM,CAAC,MAAM,WAAW,GAAW,gBAAgB,CAAC;AAYpD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,MAAe;IAC/D,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC;AAChH,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @file The greeter: the door's face, before and during a boot.
3
+ *
4
+ * The face says ChRIS. An operator is logging in to ChRIS and could not
5
+ * care less what the program at the door is called; "porter" is this
6
+ * repository's word for it and appears nowhere a user reads.
7
+ *
8
+ * One shell, two acts. At the door the brain rests at its end state beside
9
+ * a name and a password. Once the password is taken the browser is sent to
10
+ * the greet, where the brain wakes — the same frames a terminal boot draws,
11
+ * paced by the page — and the daemon's boot rows arrive beneath it as
12
+ * server-sent events, ANSI and all, rendered the way the console renders a
13
+ * transcript. `ready` hands the browser to the session; `failed` says why
14
+ * and offers the door again.
15
+ *
16
+ * The page's two scripts are the wire package's own modules, served by the
17
+ * porter from where they are installed: the brain and the ANSI renderer.
18
+ * Nothing is bundled and nothing is copied, so the greeter and the console
19
+ * draw from one source.
20
+ *
21
+ * @module
22
+ */
23
+ /**
24
+ * Escapes text for an HTML attribute or body.
25
+ *
26
+ * @param text - The text.
27
+ * @returns The text with `& < > "` escaped.
28
+ */
29
+ export declare function attribute_escape(text: string): string;
30
+ /**
31
+ * The door: the brain at rest, a name and a password.
32
+ *
33
+ * @param cubeUrl - The CUBE this door serves, shown so the operator knows where the password goes.
34
+ * @param reason - Why the last try was refused, when it was.
35
+ * @returns The page.
36
+ */
37
+ export declare function loginPage_render(cubeUrl: string, reason: string | null): string;
38
+ /**
39
+ * The greet: the brain awake, the boot rows arriving, the hand-off.
40
+ *
41
+ * @param cubeUrl - The CUBE the session is booting against.
42
+ * @param key - The session's key: where its boot streams from and where it will be mounted.
43
+ * @returns The page.
44
+ */
45
+ export declare function greetPage_render(cubeUrl: string, key: string): string;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * @file The greeter: the door's face, before and during a boot.
3
+ *
4
+ * The face says ChRIS. An operator is logging in to ChRIS and could not
5
+ * care less what the program at the door is called; "porter" is this
6
+ * repository's word for it and appears nowhere a user reads.
7
+ *
8
+ * One shell, two acts. At the door the brain rests at its end state beside
9
+ * a name and a password. Once the password is taken the browser is sent to
10
+ * the greet, where the brain wakes — the same frames a terminal boot draws,
11
+ * paced by the page — and the daemon's boot rows arrive beneath it as
12
+ * server-sent events, ANSI and all, rendered the way the console renders a
13
+ * transcript. `ready` hands the browser to the session; `failed` says why
14
+ * and offers the door again.
15
+ *
16
+ * The page's two scripts are the wire package's own modules, served by the
17
+ * porter from where they are installed: the brain and the ANSI renderer.
18
+ * Nothing is bundled and nothing is copied, so the greeter and the console
19
+ * draw from one source.
20
+ *
21
+ * @module
22
+ */
23
+ /**
24
+ * Escapes text for an HTML attribute or body.
25
+ *
26
+ * @param text - The text.
27
+ * @returns The text with `& < > "` escaped.
28
+ */
29
+ export function attribute_escape(text) {
30
+ return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
31
+ }
32
+ /** The shell around either face: the brain, the frame, the two modules. */
33
+ function shell_render(shell) {
34
+ return `<!doctype html>
35
+ <html lang="en">
36
+ <head>
37
+ <meta charset="utf-8" />
38
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
39
+ <title>${attribute_escape(shell.title)}</title>
40
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
41
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
42
+ <link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap" rel="stylesheet" />
43
+ <style>
44
+ :root { color-scheme: dark; --frame: #1d7bb9; --lit: #66ccff; --dim: #5a8ca8; --ink: #dff; --bad: #ff9c9c; }
45
+ body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: #000; color: var(--ink); font-family: "Share Tech Mono", ui-monospace, monospace; }
46
+ main { display: grid; gap: 1rem; width: min(64rem, 94vw); padding: 1.4rem 1.6rem 1.6rem; border-left: 0.6rem solid var(--frame); border-radius: 0 1.6rem 1.6rem 0; background: #05121c; }
47
+ header { display: flex; align-items: baseline; gap: 1rem; }
48
+ h1 { margin: 0; font-size: 1.1rem; letter-spacing: 0.12em; color: var(--lit); }
49
+ .cube { font-size: 0.75rem; color: var(--dim); overflow-wrap: anywhere; }
50
+ #brain { margin: 0; font-size: 0.62rem; line-height: 1.05; white-space: pre; overflow-x: auto; color: #9cf; }
51
+ form { display: grid; gap: 0.8rem; width: min(22rem, 100%); }
52
+ label { display: grid; gap: 0.25rem; font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--dim); }
53
+ input { padding: 0.5rem 0.7rem; border: 1px solid var(--frame); border-radius: 0.6rem; background: #000; color: var(--ink); font: inherit; }
54
+ button, a.pill { padding: 0.45rem 1.2rem; border: 0; border-radius: 1rem; background: var(--lit); color: #000; font: inherit; font-weight: bold; letter-spacing: 0.1em; cursor: pointer; justify-self: start; text-decoration: none; }
55
+ button:hover, a.pill:hover { filter: brightness(1.2); }
56
+ .reason { margin: 0; padding: 0.4rem 0.7rem; border-radius: 0.6rem; background: #3a0a0a; color: var(--bad); font-size: 0.85rem; }
57
+ #rows { margin: 0; font-size: 0.8rem; line-height: 1.35; white-space: pre-wrap; min-height: 6rem; max-height: 40vh; overflow-y: auto; }
58
+ #state { font-size: 0.75rem; letter-spacing: 0.15em; text-transform: uppercase; color: var(--dim); }
59
+ #state.ready { color: #33cc66; }
60
+ #state.failed { color: var(--bad); }
61
+ </style>
62
+ </head>
63
+ <body>
64
+ <main>
65
+ <header><h1>ChRIS</h1><div class="cube" id="cube"></div></header>
66
+ <pre id="brain" aria-hidden="true"></pre>
67
+ ${shell.body}
68
+ </main>
69
+ <script type="module">
70
+ import { logo_frameRender } from '${shell.root}greeter/brain.js';
71
+ import { ansi_toHtml } from '${shell.root}greeter/ansi.js';
72
+ const brain = document.getElementById('brain');
73
+ const brain_draw = (frame, resting) => { brain.innerHTML = ansi_toHtml(logo_frameRender(frame, resting).join('\\n')); };
74
+ ${shell.script}
75
+ </script>
76
+ </body>
77
+ </html>
78
+ `;
79
+ }
80
+ /**
81
+ * The door: the brain at rest, a name and a password.
82
+ *
83
+ * @param cubeUrl - The CUBE this door serves, shown so the operator knows where the password goes.
84
+ * @param reason - Why the last try was refused, when it was.
85
+ * @returns The page.
86
+ */
87
+ export function loginPage_render(cubeUrl, reason) {
88
+ const notice = reason === null ? '' : `<p class="reason" role="alert">${attribute_escape(reason)}</p>`;
89
+ return shell_render({
90
+ title: 'ChRIS · login',
91
+ root: './',
92
+ body: `<form method="post" action="login">
93
+ ${notice}
94
+ <label>Username <input name="username" autocomplete="username" required autofocus /></label>
95
+ <label>Password <input name="password" type="password" autocomplete="current-password" required /></label>
96
+ <button type="submit">LOG IN</button>
97
+ </form>`,
98
+ script: `document.getElementById('cube').textContent = ${JSON.stringify(cubeUrl)};
99
+ brain_draw(0, true);`,
100
+ });
101
+ }
102
+ /**
103
+ * The greet: the brain awake, the boot rows arriving, the hand-off.
104
+ *
105
+ * @param cubeUrl - The CUBE the session is booting against.
106
+ * @param key - The session's key: where its boot streams from and where it will be mounted.
107
+ * @returns The page.
108
+ */
109
+ export function greetPage_render(cubeUrl, key) {
110
+ return shell_render({
111
+ title: 'ChRIS · starting your session',
112
+ root: '../',
113
+ body: `<div id="state">starting your session</div>
114
+ <pre id="rows"></pre>
115
+ <a class="pill" id="again" href="../login" hidden>BACK TO THE DOOR</a>`,
116
+ script: `document.getElementById('cube').textContent = ${JSON.stringify(cubeUrl)};
117
+ const rows = document.getElementById('rows');
118
+ const state = document.getElementById('state');
119
+ const again = document.getElementById('again');
120
+ let frame = 0;
121
+ let awake = true;
122
+ const pulse = setInterval(() => { if (awake) brain_draw(frame++, false); }, 120);
123
+ brain_draw(0, false);
124
+ const feed = new EventSource(${JSON.stringify(`../boot/${key}`)});
125
+ feed.addEventListener('line', (event) => {
126
+ const line = JSON.parse(event.data);
127
+ rows.insertAdjacentHTML('beforeend', ansi_toHtml(line.text) + '\\n');
128
+ rows.scrollTop = rows.scrollHeight;
129
+ });
130
+ const settle = (name, reason) => {
131
+ feed.close();
132
+ awake = false;
133
+ clearInterval(pulse);
134
+ brain_draw(0, true);
135
+ state.textContent = name === 'ready' ? 'your session is ready' : ('your session did not start' + (reason ? ' — ' + reason : ''));
136
+ state.className = name;
137
+ if (name === 'ready') {
138
+ setTimeout(() => { window.location.assign(${JSON.stringify(`../s/${key}/?door`)}); }, 700);
139
+ } else {
140
+ again.hidden = false;
141
+ }
142
+ };
143
+ feed.addEventListener('ready', () => settle('ready', null));
144
+ feed.addEventListener('failed', (event) => settle('failed', JSON.parse(event.data).reason));
145
+ feed.onerror = () => { if (state.className === '') settle('failed', 'the boot stream closed'); };`,
146
+ });
147
+ }
148
+ //# sourceMappingURL=greeter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"greeter.js","sourceRoot":"","sources":["../src/greeter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAkBH;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACzG,CAAC;AAED,2EAA2E;AAC3E,SAAS,YAAY,CAAC,KAAmB;IACvC,OAAO;;;;;SAKA,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BlC,KAAK,CAAC,IAAI;;;oCAGsB,KAAK,CAAC,IAAI;+BACf,KAAK,CAAC,IAAI;;;EAGvC,KAAK,CAAC,MAAM;;;;CAIb,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,MAAqB;IACrE,MAAM,MAAM,GAAW,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC;IAC/G,OAAO,YAAY,CAAC;QAClB,KAAK,EAAE,eAAe;QACtB,IAAI,EAAE,IAAI;QACV,IAAI,EAAE;MACJ,MAAM;;;;UAIF;QACN,MAAM,EAAE,iDAAiD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;qBAC/D;KAClB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,GAAW;IAC3D,OAAO,YAAY,CAAC;QAClB,KAAK,EAAE,+BAA+B;QACtC,IAAI,EAAE,KAAK;QACX,IAAI,EAAE;;yEAE+D;QACrE,MAAM,EAAE,iDAAiD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;+BAQrD,IAAI,CAAC,SAAS,CAAC,WAAW,GAAG,EAAE,CAAC;;;;;;;;;;;;;;gDAcf,IAAI,CAAC,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;;;;;;;kGAOe;KAC/F,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,86 @@
1
+ import type { Berth, BootListener, BootReport, SessionHost, SessionSighting } from './sessionHost.js';
2
+ /** How many boot lines a session keeps for late followers. */
3
+ export declare const BOOT_LINES_KEPT: number;
4
+ /** The four directories a session owns. */
5
+ export interface SessionDirs {
6
+ config: string;
7
+ runtime: string;
8
+ cache: string;
9
+ tmp: string;
10
+ }
11
+ /** What the host needs of a child it started. */
12
+ export interface SpawnedSession {
13
+ pid: number | undefined;
14
+ stdout: NodeJS.ReadableStream | null;
15
+ stderr: NodeJS.ReadableStream | null;
16
+ stdin: NodeJS.WritableStream | null;
17
+ exitCode: number | null;
18
+ kill(signal?: NodeJS.Signals): boolean;
19
+ once(event: 'exit', listener: (code: number | null) => void): unknown;
20
+ }
21
+ /** A process spawner with the shape of `child_process.spawn`. */
22
+ export type SessionSpawn = (command: string, args: string[], options: {
23
+ env: NodeJS.ProcessEnv;
24
+ stdio: ['pipe', 'pipe', 'pipe'];
25
+ }) => SpawnedSession;
26
+ /** Whether a berth's daemon answers on the wire. */
27
+ export type LivenessProbe = (url: string) => Promise<boolean>;
28
+ /** What the process host is built from. */
29
+ export interface ProcessHostOptions {
30
+ /** Where each identity's subtree goes. */
31
+ stateDir: string;
32
+ /** The chell entry to run. */
33
+ chellEntry: string;
34
+ /** The spawner; `child_process.spawn` by default. */
35
+ spawn?: SessionSpawn;
36
+ /** The liveness probe; a TCP connect to the berth by default. */
37
+ alive?: LivenessProbe;
38
+ /** How long a boot may take before it is called failed, in ms. */
39
+ bootTimeoutMs?: number;
40
+ /** How often to look for the berth while booting, in ms. */
41
+ pollMs?: number;
42
+ /** How to signal a process this host did not start; `process.kill` by default. */
43
+ kill?: (pid: number, signal: NodeJS.Signals) => void;
44
+ }
45
+ /** Sessions as child processes on this host. */
46
+ export declare class ProcessHost implements SessionHost {
47
+ private readonly stateDir;
48
+ private readonly chellEntry;
49
+ private readonly spawner;
50
+ private readonly alive;
51
+ private readonly bootTimeoutMs;
52
+ private readonly pollMs;
53
+ private readonly kill;
54
+ private readonly sessions;
55
+ constructor(options: ProcessHostOptions);
56
+ /**
57
+ * The four directories an identity's session owns, under the state dir.
58
+ *
59
+ * @param identity - The normalised identity.
60
+ * @returns The directories; not necessarily existing yet.
61
+ */
62
+ dirs_of(identity: string): SessionDirs;
63
+ /** Reads a berth file, if well formed. */
64
+ private berthFile_read;
65
+ /** Reads an identity's berth from its own runtime directory, if written. */
66
+ private berth_read;
67
+ /** @inheritdoc */
68
+ sessions_adopt(): Promise<SessionSighting[]>;
69
+ /** @inheritdoc */
70
+ find(identity: string): Promise<Berth | null>;
71
+ /** @inheritdoc */
72
+ spawn(identity: string, user: string, cubeUrl: string, token: string): Promise<Berth>;
73
+ /** @inheritdoc */
74
+ spawn_begin(identity: string, user: string, cubeUrl: string, token: string): void;
75
+ /** Starts the child and waits for its berth to answer. */
76
+ private boot_run;
77
+ /** Settles a boot and tells everyone following it. */
78
+ private boot_end;
79
+ /** @inheritdoc */
80
+ boot_follow(identity: string, listener: BootListener): {
81
+ report: BootReport;
82
+ release: () => void;
83
+ } | null;
84
+ /** @inheritdoc */
85
+ evict(identity: string): Promise<boolean>;
86
+ }