nylorun 0.4.0-beta → 0.6.0-beta
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 +39 -0
- package/README.md +207 -105
- package/dist/cli.js +24 -22
- package/dist/doctor.d.ts +10 -8
- package/dist/doctor.js +54 -37
- package/dist/home.d.ts +1 -1
- package/dist/home.js +1 -1
- package/dist/project/derived-key.d.ts +2 -2
- package/dist/project/derived-key.js +2 -2
- package/dist/project/link.d.ts +7 -7
- package/dist/project/link.js +3 -3
- package/dist/stack/commands.d.ts +23 -15
- package/dist/stack/commands.js +332 -214
- package/dist/stack/compose-file.d.ts +11 -8
- package/dist/stack/compose-file.js +54 -21
- package/dist/stack/docker.d.ts +10 -0
- package/dist/stack/docker.js +64 -1
- package/dist/stack/env-file.d.ts +12 -2
- package/dist/stack/env-file.js +13 -3
- package/dist/stack/host-files.d.ts +4 -4
- package/dist/stack/host-files.js +3 -3
- package/dist/stack/images.d.ts +4 -2
- package/dist/stack/images.js +3 -2
- package/dist/stack/index.d.ts +4 -3
- package/dist/stack/index.js +10 -4
- package/dist/stack/paths.d.ts +3 -3
- package/dist/stack/paths.js +1 -1
- package/dist/stack/ports.d.ts +4 -2
- package/dist/stack/ports.js +3 -1
- package/dist/stack/prepare.d.ts +7 -3
- package/dist/stack/prepare.js +5 -3
- package/dist/stack/proxy.d.ts +78 -0
- package/dist/stack/proxy.js +224 -0
- package/dist/stack/stacks.d.ts +37 -34
- package/dist/stack/stacks.js +91 -57
- package/dist/stack/studio-login.d.ts +4 -3
- package/dist/stack/studio-login.js +5 -4
- package/dist/stack/versions.d.ts +1 -1
- package/dist/stack/versions.js +1 -1
- package/dist/telemetry.d.ts +31 -0
- package/dist/telemetry.js +79 -0
- package/package.json +5 -5
package/dist/doctor.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CliError } from "./errors.js";
|
|
2
|
-
import { checkDocker, defaultStackDeps, readStackStatus, } from "./stack/index.js";
|
|
3
|
-
/** Oldest Node
|
|
2
|
+
import { checkDocker, defaultStackDeps, readProxyReport, readStackStatus, } from "./stack/index.js";
|
|
3
|
+
/** Oldest Node nylorun and the developer's application run on. */
|
|
4
4
|
const MIN_NODE_MAJOR = 24;
|
|
5
5
|
/**
|
|
6
|
-
* `nylorun doctor`: check the prerequisites of
|
|
7
|
-
* Docker, Compose v2) and, when they pass, the
|
|
6
|
+
* `nylorun doctor`: check the prerequisites of a local Tenant (Node 24+,
|
|
7
|
+
* Docker, Compose v2) and, when they pass, the Tenant's health. Prints the fix
|
|
8
8
|
* for each problem and returns 1 when a prerequisite is missing or a running
|
|
9
|
-
*
|
|
9
|
+
* Tenant is unhealthy; installs and starts nothing.
|
|
10
10
|
*/
|
|
11
11
|
export async function doctorStack(options) {
|
|
12
12
|
const log = options.log ?? ((line) => console.log(line));
|
|
@@ -20,7 +20,7 @@ export async function doctorStack(options) {
|
|
|
20
20
|
if (checks.docker.ok && checks.compose?.ok) {
|
|
21
21
|
try {
|
|
22
22
|
const status = await readStackStatus(deps);
|
|
23
|
-
report.
|
|
23
|
+
report.tenant = {
|
|
24
24
|
name: status.name,
|
|
25
25
|
project: status.project,
|
|
26
26
|
home: status.home,
|
|
@@ -34,14 +34,15 @@ export async function doctorStack(options) {
|
|
|
34
34
|
catch (error) {
|
|
35
35
|
if (!(error instanceof CliError) || error.exitCode !== 2)
|
|
36
36
|
throw error;
|
|
37
|
-
report.
|
|
37
|
+
report.noTenant = error.message;
|
|
38
38
|
}
|
|
39
|
+
report.proxy = await readProxyReport(deps);
|
|
39
40
|
}
|
|
40
|
-
const
|
|
41
|
-
(!report.
|
|
42
|
-
!report.
|
|
43
|
-
report.
|
|
44
|
-
const failed = !nodeOk || !checks.docker.ok || checks.compose?.ok === false ||
|
|
41
|
+
const broken = report.tenant?.state === "running" &&
|
|
42
|
+
(!report.tenant.runtime.healthy ||
|
|
43
|
+
!report.tenant.gateway.healthy ||
|
|
44
|
+
report.tenant.tenant?.cause !== undefined);
|
|
45
|
+
const failed = !nodeOk || !checks.docker.ok || checks.compose?.ok === false || broken;
|
|
45
46
|
if (options.json) {
|
|
46
47
|
log(JSON.stringify(report, null, 2));
|
|
47
48
|
return failed ? 1 : 0;
|
|
@@ -61,43 +62,59 @@ export async function doctorStack(options) {
|
|
|
61
62
|
["docker", line(checks.docker)],
|
|
62
63
|
["compose", line(checks.compose)],
|
|
63
64
|
];
|
|
64
|
-
const
|
|
65
|
-
if (report.
|
|
66
|
-
rows.push(["
|
|
67
|
-
if (
|
|
65
|
+
const local = report.tenant;
|
|
66
|
+
if (report.noTenant)
|
|
67
|
+
rows.push(["tenant", `- ${report.noTenant}`]);
|
|
68
|
+
if (local) {
|
|
68
69
|
rows.push([
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
? `- ${
|
|
72
|
-
:
|
|
73
|
-
? `- ${
|
|
74
|
-
:
|
|
75
|
-
? `✓ ${
|
|
76
|
-
: `✗ ${
|
|
70
|
+
"tenant",
|
|
71
|
+
local.state === "absent"
|
|
72
|
+
? `- ${local.name} not created under ${local.home}: run nylorun up`
|
|
73
|
+
: local.state === "stopped"
|
|
74
|
+
? `- ${local.name} stopped (Compose project ${local.project}): run nylorun up`
|
|
75
|
+
: local.runtime.healthy
|
|
76
|
+
? `✓ ${local.name} running (Compose project ${local.project})`
|
|
77
|
+
: `✗ ${local.name} running, but the Runtime does not answer: see nylorun status and nylorun logs runtime`,
|
|
77
78
|
]);
|
|
78
|
-
if (
|
|
79
|
+
if (local.state === "running") {
|
|
79
80
|
rows.push([
|
|
80
81
|
"runtime",
|
|
81
|
-
|
|
82
|
-
? `✓ ${
|
|
83
|
-
: `✗ ${
|
|
82
|
+
local.runtime.healthy
|
|
83
|
+
? `✓ ${local.runtime.url ?? "?"} · ${local.runtime.version ?? "?"}`
|
|
84
|
+
: `✗ ${local.runtime.url ?? "?"} not answering`,
|
|
84
85
|
]);
|
|
85
86
|
rows.push([
|
|
86
87
|
"gateway",
|
|
87
|
-
|
|
88
|
-
? `✓ ${
|
|
89
|
-
: `✗ ${
|
|
88
|
+
local.gateway.healthy
|
|
89
|
+
? `✓ ${local.gateway.state} · combined packing (runtime: core,loop; gateway: gates)`
|
|
90
|
+
: `✗ ${local.gateway.state}: model calls fail; see nylorun logs gateway`,
|
|
90
91
|
]);
|
|
91
|
-
if (
|
|
92
|
+
if (local.tenant)
|
|
92
93
|
rows.push([
|
|
93
|
-
"tenant",
|
|
94
|
-
|
|
95
|
-
? `✓ ${
|
|
96
|
-
: `✗ ${
|
|
94
|
+
"tenant id",
|
|
95
|
+
local.tenant.state === "open"
|
|
96
|
+
? `✓ ${local.tenant.id ?? "?"} open`
|
|
97
|
+
: `✗ ${local.tenant.id ?? "?"} unavailable${local.tenant.cause ? `: ${local.tenant.cause.code}: ${local.tenant.cause.repair}` : " (opening)"}`,
|
|
97
98
|
]);
|
|
98
|
-
rows.push(["studio", `${
|
|
99
|
+
rows.push(["studio", `${local.studio.proxyUrl ?? local.studio.url ?? "?"} · ${local.studio.state}`]);
|
|
99
100
|
}
|
|
100
101
|
}
|
|
102
|
+
const proxy = report.proxy;
|
|
103
|
+
if (proxy) {
|
|
104
|
+
const on = proxy.port
|
|
105
|
+
? `127.0.0.1:${proxy.port}${proxy.ipv6 ? ` and [::1]:${proxy.port}` : ""}`
|
|
106
|
+
: "";
|
|
107
|
+
rows.push([
|
|
108
|
+
"proxy",
|
|
109
|
+
proxy.state === "running"
|
|
110
|
+
? `✓ running on ${on} (http://<tenant>.localhost:${proxy.port ?? "?"})`
|
|
111
|
+
: proxy.state === "disabled"
|
|
112
|
+
? "- disabled (NYLORUN_PROXY_DISABLED): Studio is on each Tenant's own port"
|
|
113
|
+
: proxy.state === "stopped"
|
|
114
|
+
? `- stopped${on ? ` (${on})` : ""}: nylorun start starts it`
|
|
115
|
+
: "- not created yet: nylorun start creates it",
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
101
118
|
const width = Math.max(...rows.map(([key]) => key.length)) + 2;
|
|
102
119
|
for (const [key, value] of rows)
|
|
103
120
|
log(` ${key.padEnd(width)}${value}`);
|
package/dist/home.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`.
|
|
2
|
+
* The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`. Compose
|
|
3
3
|
* bind-mounts it into the Runtime and Studio containers, and `@nylorun/admin`
|
|
4
4
|
* reads `host.json` and the admin key from it.
|
|
5
5
|
*/
|
package/dist/home.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
/**
|
|
4
|
-
* The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`.
|
|
4
|
+
* The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`. Compose
|
|
5
5
|
* bind-mounts it into the Runtime and Studio containers, and `@nylorun/admin`
|
|
6
6
|
* reads `host.json` and the admin key from it.
|
|
7
7
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/** The derived principal a Project uses; the
|
|
1
|
+
/** The derived principal a Project uses; the local Runtime registers it on its Tenant. */
|
|
2
2
|
export declare const PROJECT_PRINCIPAL_ID = "project";
|
|
3
3
|
/**
|
|
4
|
-
* Key of a derived principal on the
|
|
4
|
+
* Key of a derived principal on the local Tenant, from the admin key. A copy of
|
|
5
5
|
* `deriveTenantKey` in `@nylorun/admin` (nylorun depends on `@nylorun/core` only); both are
|
|
6
6
|
* tested against the same fixed vector.
|
|
7
7
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createHmac } from "node:crypto";
|
|
2
|
-
/** The derived principal a Project uses; the
|
|
2
|
+
/** The derived principal a Project uses; the local Runtime registers it on its Tenant. */
|
|
3
3
|
export const PROJECT_PRINCIPAL_ID = "project";
|
|
4
4
|
/**
|
|
5
|
-
* Key of a derived principal on the
|
|
5
|
+
* Key of a derived principal on the local Tenant, from the admin key. A copy of
|
|
6
6
|
* `deriveTenantKey` in `@nylorun/admin` (nylorun depends on `@nylorun/core` only); both are
|
|
7
7
|
* tested against the same fixed vector.
|
|
8
8
|
*/
|
package/dist/project/link.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Project link (`.nylorun/link.json`) and credentials (`.nylorun/credentials.json`).
|
|
3
|
-
* `nylorun start` writes both, format
|
|
4
|
-
* the Tenant id as information (nothing selects a Tenant).
|
|
5
|
-
*
|
|
3
|
+
* `nylorun start` writes both, format 3: the local Tenant's name, its URL and Host id, and
|
|
4
|
+
* the Tenant id as information (nothing in a request selects a Tenant). `start` replaces a link
|
|
5
|
+
* of an older format.
|
|
6
6
|
*/
|
|
7
7
|
export interface ProjectLink {
|
|
8
|
-
format: 0 | 1 | 2;
|
|
9
|
-
/** The local
|
|
10
|
-
|
|
8
|
+
format: 0 | 1 | 2 | 3;
|
|
9
|
+
/** The local Tenant's name (format 3). */
|
|
10
|
+
tenant?: string;
|
|
11
11
|
hostUrl: string;
|
|
12
12
|
hostId: string;
|
|
13
13
|
tenantId?: string;
|
|
@@ -17,7 +17,7 @@ export declare function credentialsPath(projectRoot: string): string;
|
|
|
17
17
|
/** The Project's link, or undefined when it has none. An unreadable link is an error. */
|
|
18
18
|
export declare function readProjectLink(projectRoot: string): Promise<ProjectLink | undefined>;
|
|
19
19
|
export declare function writeProjectLink(projectRoot: string, link: {
|
|
20
|
-
|
|
20
|
+
tenant: string;
|
|
21
21
|
hostUrl: string;
|
|
22
22
|
hostId: string;
|
|
23
23
|
tenantId: string;
|
package/dist/project/link.js
CHANGED
|
@@ -33,7 +33,7 @@ export async function readProjectLink(projectRoot) {
|
|
|
33
33
|
const link = parsed.data;
|
|
34
34
|
return {
|
|
35
35
|
format: link.format,
|
|
36
|
-
...(link.
|
|
36
|
+
...(link.format === 3 && link.tenant ? { tenant: link.tenant } : {}),
|
|
37
37
|
hostUrl: link.hostUrl.replace(/\/$/, ""),
|
|
38
38
|
hostId: link.hostId,
|
|
39
39
|
...(link.tenantId ? { tenantId: link.tenantId } : {}),
|
|
@@ -60,8 +60,8 @@ async function ensureProjectDir(projectRoot) {
|
|
|
60
60
|
export async function writeProjectLink(projectRoot, link) {
|
|
61
61
|
await ensureProjectDir(projectRoot);
|
|
62
62
|
await writePrivate(linkPath(projectRoot), {
|
|
63
|
-
format:
|
|
64
|
-
|
|
63
|
+
format: 3,
|
|
64
|
+
tenant: link.tenant,
|
|
65
65
|
hostUrl: link.hostUrl.replace(/\/$/, ""),
|
|
66
66
|
hostId: link.hostId,
|
|
67
67
|
tenantId: link.tenantId,
|
package/dist/stack/commands.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { HostTenant } from "@nylorun/core/contracts";
|
|
2
2
|
import { type ComposeService, type DockerRunner } from "./docker.js";
|
|
3
3
|
import type { PortProbe } from "./ports.js";
|
|
4
|
+
import { type ProxyStatus } from "./proxy.js";
|
|
4
5
|
import { type FetchLike } from "./studio-login.js";
|
|
5
|
-
export declare const STACK_SERVICES: readonly ["postgres", "restate", "s2", "gateway", "runtime", "studio"];
|
|
6
|
+
export declare const STACK_SERVICES: readonly ["postgres", "restate", "s2-lite", "gateway", "runtime", "studio"];
|
|
6
7
|
export declare const stackUsage: string;
|
|
7
8
|
export interface StackDeps {
|
|
8
|
-
/** Environment snapshot (NYLORUN_HOME,
|
|
9
|
+
/** Environment snapshot (NYLORUN_HOME, NYLORUN_TENANT, image overrides, NYLORUN_COMPOSE_PROJECT). */
|
|
9
10
|
env: Readonly<Record<string, string | undefined>>;
|
|
10
11
|
docker: DockerRunner;
|
|
11
12
|
fetch: FetchLike;
|
|
@@ -26,7 +27,7 @@ export interface StackDeps {
|
|
|
26
27
|
pidAlive(pid: number): boolean;
|
|
27
28
|
/** Where the project is looked for (default: the process's working directory). */
|
|
28
29
|
cwd?: string;
|
|
29
|
-
/** `~/.nylorun`: the
|
|
30
|
+
/** `~/.nylorun`: the Tenants (tests use a temporary directory). */
|
|
30
31
|
nylorunRoot?: string;
|
|
31
32
|
/** Delay between health polls; tests shorten it. */
|
|
32
33
|
pollMs?: number;
|
|
@@ -35,7 +36,7 @@ export interface StackDeps {
|
|
|
35
36
|
/** How long a Studio login is retried before warning. */
|
|
36
37
|
loginTimeoutMs?: number;
|
|
37
38
|
}
|
|
38
|
-
/** The Compose project of
|
|
39
|
+
/** The Compose project of Tenant `name`: `nylorun-<name>`, or `NYLORUN_COMPOSE_PROJECT`. */
|
|
39
40
|
export declare function stackProject(env: StackDeps["env"], name: string): string;
|
|
40
41
|
interface Flags {
|
|
41
42
|
rest: string[];
|
|
@@ -55,7 +56,7 @@ export type StackTenant = Pick<HostTenant, "id" | "name" | "state" | "cause">;
|
|
|
55
56
|
/** Printed by `start` when it does not open Studio itself. */
|
|
56
57
|
export declare const STUDIO_SIGN_IN_HINT = "To sign a browser in to Studio, run \"npx nylorun studio\".";
|
|
57
58
|
export interface StackStatus {
|
|
58
|
-
/** The
|
|
59
|
+
/** The Tenant's name. */
|
|
59
60
|
name: string;
|
|
60
61
|
/** The Compose project. */
|
|
61
62
|
project: string;
|
|
@@ -64,16 +65,19 @@ export interface StackStatus {
|
|
|
64
65
|
state: "running" | "stopped" | "absent";
|
|
65
66
|
runtime: {
|
|
66
67
|
url?: string;
|
|
67
|
-
/** The Admin API (operator listener), when the
|
|
68
|
+
/** The Admin API (operator listener), when the Tenant publishes one. */
|
|
68
69
|
adminUrl?: string;
|
|
69
70
|
healthy: boolean;
|
|
70
71
|
version?: string;
|
|
71
72
|
hostId?: string;
|
|
72
73
|
};
|
|
73
|
-
/** The
|
|
74
|
+
/** The Tenant as the Runtime reports it, while it answers. */
|
|
74
75
|
tenant?: StackTenant;
|
|
75
76
|
studio: {
|
|
77
|
+
/** Studio's own port: what an embedding app frames (same site as its own localhost). */
|
|
76
78
|
url?: string;
|
|
79
|
+
/** Through the Studio proxy, when it serves the Tenant. */
|
|
80
|
+
proxyUrl?: string;
|
|
77
81
|
state: string;
|
|
78
82
|
/** Exact origins that may show Studio in a frame (Studio §8.9). */
|
|
79
83
|
embedOrigins?: string[];
|
|
@@ -88,13 +92,15 @@ export interface StackStatus {
|
|
|
88
92
|
};
|
|
89
93
|
services: ComposeService[];
|
|
90
94
|
}
|
|
95
|
+
/** The Studio proxy, as data (`nylorun doctor`). */
|
|
96
|
+
export declare function readProxyReport(deps: StackDeps): Promise<ProxyStatus>;
|
|
91
97
|
/** What `nylorun status` reports, as data (`nylorun doctor`). */
|
|
92
98
|
export declare function readStackStatus(deps: StackDeps, options?: {
|
|
93
99
|
name?: string;
|
|
94
100
|
}): Promise<StackStatus>;
|
|
95
|
-
/** The running
|
|
101
|
+
/** The running Tenant as clients reach it. */
|
|
96
102
|
export interface StackEndpoints {
|
|
97
|
-
/** The
|
|
103
|
+
/** The Tenant's name. */
|
|
98
104
|
name: string;
|
|
99
105
|
/** The Host root. */
|
|
100
106
|
home: string;
|
|
@@ -105,13 +111,15 @@ export interface StackEndpoints {
|
|
|
105
111
|
hostId: string;
|
|
106
112
|
adminKey: string;
|
|
107
113
|
studioPort: number;
|
|
114
|
+
/** Through the proxy when it serves the Tenant, else Studio's own port. */
|
|
115
|
+
studioUrl: string;
|
|
108
116
|
/** Studio is running and healthy. */
|
|
109
117
|
studioUp: boolean;
|
|
110
118
|
/** This call started the Runtime (it was not running before). */
|
|
111
119
|
started: boolean;
|
|
112
120
|
}
|
|
113
121
|
/**
|
|
114
|
-
* Start the selected
|
|
122
|
+
* Start the selected Tenant unless it is already running (`nylorun studio`): the
|
|
115
123
|
* `start` code path without its output, its Tenant wait or the Project link. Compose
|
|
116
124
|
* progress still streams, since the first run pulls images.
|
|
117
125
|
*/
|
|
@@ -121,18 +129,18 @@ export declare function ensureStack(deps: StackDeps, options: {
|
|
|
121
129
|
}): Promise<StackEndpoints>;
|
|
122
130
|
/** Add Studio's `next` path (e.g. `/tenants/<id>`) to a login URL. */
|
|
123
131
|
export declare function withNext(loginUrl: string, next: string | undefined): string;
|
|
124
|
-
/** The Studio page
|
|
132
|
+
/** The Tenant's Studio page, as a login `next` path. */
|
|
125
133
|
export declare function tenantStudioPath(tenantId: string): string;
|
|
126
134
|
/**
|
|
127
|
-
* Mint a fresh Studio login URL on a running
|
|
135
|
+
* Mint a fresh Studio login URL on a running Tenant, landing on `next`.
|
|
128
136
|
* Undefined (after a warning) when Studio does not answer.
|
|
129
137
|
*/
|
|
130
|
-
export declare function studioLoginUrl(deps: StackDeps,
|
|
131
|
-
/** `nylorun studio`, landing on `next` when given, else on the
|
|
138
|
+
export declare function studioLoginUrl(deps: StackDeps, running: Pick<StackEndpoints, "studioPort" | "studioUrl" | "adminKey">, next?: string): Promise<string | undefined>;
|
|
139
|
+
/** `nylorun studio`, landing on `next` when given, else on the Tenant's page. */
|
|
132
140
|
export declare function runStudioCommand(args: readonly string[], deps: StackDeps, options?: {
|
|
133
141
|
next?: string;
|
|
134
142
|
}): Promise<number>;
|
|
135
143
|
export declare function isStackCommand(name: string | undefined): boolean;
|
|
136
|
-
/** Run one
|
|
144
|
+
/** Run one Tenant command (`up`/`start`, `down`/`stop`, `status`, `logs`, `reset`, `studio`, `ls`, `delete`). */
|
|
137
145
|
export declare function runStackCommand(name: string, args: readonly string[], deps: StackDeps): Promise<number>;
|
|
138
146
|
export {};
|