nylorun 0.12.0-beta → 0.12.1-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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # nylorun
2
2
 
3
+ ## 0.12.1-beta
4
+
5
+ ### Patch Changes
6
+
7
+ - 7780b2f: **One client and connection layer.** The Project link and credentials are read one way, and every Runtime client shares one `/health` probe.
8
+
9
+ - `@nylorun/core`: `@nylorun/core/project` (Node only, the one Core subpath that imports Node modules) reads the Nylorun home, a local Tenant's Host root (`tenantHostRoot`), the Project root (`findProjectRoot`) and the Project link and credentials (`findLinkedProject`, `readProjectLink`, `readCredentialsFile`), validated with `ProjectLinkFileSchema` and `ProjectCredentialsFileSchema`; a broken or newer file throws `ProjectFileError`. `@nylorun/core/transport` (browser-safe) holds the `/health` compatibility probe (`checkHealth`), `parseProtocolRange` (on `ProtocolRangeSchema`, ignoring fields a newer Host adds), `describeIncompatibility`, `requestHeaders` and `readBody`.
10
+ - `@nylorun/agents`: `resolveConnection` and `createClient()` find the Project as every reader does: the nearest directory with `.nylorun/` from `cwd` upwards, never the home directory or above it (they used to walk to the filesystem root, and past a `.nylorun/` without a link). A link without `credentials.json`, or a link or credentials file that does not validate, is now `connection_missing` naming the file and `npx nylorun start`, instead of a raw file-system or parse error. `@nylorun/agents/client` loads the link reader only when `createClient()` resolves a connection, so it imports no Node module. The root entry re-exports `checkHealth`, `describeIncompatibility` and `parseProtocolRange`.
11
+ - `@nylorun/admin`: `createAdmin` reads the Project link with the same reader. A link that does not validate is now refused like one from an older nylorun (when nothing else names the Host root), and a linked Project's `credentials.json` that does not validate is `connection_missing` instead of being skipped. `@nylorun/admin/project` re-exports `@nylorun/core/project` for tools that depend on this package. The `/health` check and request headers come from `@nylorun/core/transport`.
12
+ - `nylorun`: reads the Project link and credentials with `@nylorun/core/project`; a credentials file whose keys are not 64 hex characters is replaced by `start`, as an unreadable one was. No command changes.
13
+ - `@nylorun/cli`: `nylo` reads the Project root, link and credentials through `@nylorun/admin/project` instead of its own copies, with the same messages. No command changes.
14
+ - `@nylorun/studio`: the server's Runtime compatibility probe is `checkHealth` from `@nylorun/agents`.
15
+
16
+ - Pin core to the tested release.
17
+ - Pin runtime to the tested release.
18
+ - Pin studio to the tested release.
19
+ - Updated dependencies [7780b2f]
20
+ - Updated dependencies [070674d]
21
+ - @nylorun/core@0.18.0-beta
22
+
3
23
  ## 0.12.0-beta
4
24
 
5
25
  ### Major Changes
@@ -1,19 +1,12 @@
1
+ import { projectCredentialsPath, projectLinkPath, type ProjectLink } from "@nylorun/core/project";
1
2
  /**
2
3
  * The Project link (`.nylorun/link.json`) and credentials (`.nylorun/credentials.json`).
3
4
  * `nylorun start` writes both, format 3: the local Tenant's name, its URL and Host id, and
4
5
  * the Tenant id as information (nothing in a request selects a Tenant). `start` replaces a link
5
- * of an older format.
6
+ * of an older format. Reading is `@nylorun/core/project`'s, which every client shares.
6
7
  */
7
- export interface ProjectLink {
8
- format: 0 | 1 | 2 | 3;
9
- /** The local Tenant's name (format 3). */
10
- tenant?: string;
11
- hostUrl: string;
12
- hostId: string;
13
- tenantId?: string;
14
- }
15
- export declare function linkPath(projectRoot: string): string;
16
- export declare function credentialsPath(projectRoot: string): string;
8
+ export type { ProjectLink };
9
+ export { projectLinkPath as linkPath, projectCredentialsPath as credentialsPath };
17
10
  /** The Project's link, or undefined when it has none. An unreadable link is an error. */
18
11
  export declare function readProjectLink(projectRoot: string): Promise<ProjectLink | undefined>;
19
12
  export declare function writeProjectLink(projectRoot: string, link: {
@@ -37,9 +30,8 @@ export interface KeyCredentials {
37
30
  /** The Project's keys, or undefined when absent or unreadable. */
38
31
  export declare function readProjectCredentials(projectRoot: string): Promise<KeyCredentials | undefined>;
39
32
  /**
40
- * A credentials file (`{ format: 1, applicationKey, principalId, managementKey?,
41
- * managementPrincipalId? }`): the Project's, or one the nylorun commands keep in the Host root.
42
- * Undefined when absent or unreadable.
33
+ * A credentials file (format 0 or 1): the Project's, or one the nylorun commands keep in the
34
+ * Host root. Undefined when absent or unreadable, so `start` replaces it.
43
35
  */
44
36
  export declare function readCredentialsFile(path: string): Promise<KeyCredentials | undefined>;
45
37
  /** `.nylorun/credentials.json` (format 1, mode 0600). */
@@ -1,43 +1,19 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
2
+ import { chmod, mkdir, rename, rm, writeFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
- import { ProjectLinkFileSchema } from "@nylorun/core/contracts";
4
+ import { ProjectFileError, projectCredentialsPath, projectLinkPath, readCredentialsFile as readCredentials, readProjectLink as readLink, } from "@nylorun/core/project";
5
5
  import { CliError } from "../errors.js";
6
- export function linkPath(projectRoot) {
7
- return join(projectRoot, ".nylorun", "link.json");
8
- }
9
- export function credentialsPath(projectRoot) {
10
- return join(projectRoot, ".nylorun", "credentials.json");
11
- }
6
+ export { projectLinkPath as linkPath, projectCredentialsPath as credentialsPath };
12
7
  /** The Project's link, or undefined when it has none. An unreadable link is an error. */
13
8
  export async function readProjectLink(projectRoot) {
14
- let text;
15
9
  try {
16
- text = await readFile(linkPath(projectRoot), "utf8");
10
+ return readLink(projectRoot);
17
11
  }
18
12
  catch (error) {
19
- if (error.code === "ENOENT")
20
- return undefined;
13
+ if (error instanceof ProjectFileError)
14
+ throw new CliError(`Invalid or newer Project link at ${error.path}. Upgrade nylorun, or remove the file and run "npx nylorun start" again.`, 1);
21
15
  throw error;
22
16
  }
23
- let value;
24
- try {
25
- value = JSON.parse(text);
26
- }
27
- catch {
28
- value = undefined;
29
- }
30
- const parsed = ProjectLinkFileSchema.safeParse(value);
31
- if (!parsed.success)
32
- throw new CliError(`Invalid or newer Project link at ${linkPath(projectRoot)}. Upgrade nylorun, or remove the file and run "npx nylorun start" again.`, 1);
33
- const link = parsed.data;
34
- return {
35
- format: link.format,
36
- ...(link.format === 3 && link.tenant ? { tenant: link.tenant } : {}),
37
- hostUrl: link.hostUrl.replace(/\/$/, ""),
38
- hostId: link.hostId,
39
- ...(link.tenantId ? { tenantId: link.tenantId } : {}),
40
- };
41
17
  }
42
18
  async function writePrivate(path, value) {
43
19
  const temporary = `${path}.${randomBytes(8).toString("hex")}.tmp`;
@@ -59,7 +35,7 @@ async function ensureProjectDir(projectRoot) {
59
35
  }
60
36
  export async function writeProjectLink(projectRoot, link) {
61
37
  await ensureProjectDir(projectRoot);
62
- await writePrivate(linkPath(projectRoot), {
38
+ await writePrivate(projectLinkPath(projectRoot), {
63
39
  format: 3,
64
40
  tenant: link.tenant,
65
41
  hostUrl: link.hostUrl.replace(/\/$/, ""),
@@ -69,34 +45,34 @@ export async function writeProjectLink(projectRoot, link) {
69
45
  }
70
46
  /** The Project's keys, or undefined when absent or unreadable. */
71
47
  export async function readProjectCredentials(projectRoot) {
72
- return await readCredentialsFile(credentialsPath(projectRoot));
48
+ return await readCredentialsFile(projectCredentialsPath(projectRoot));
73
49
  }
74
50
  /**
75
- * A credentials file (`{ format: 1, applicationKey, principalId, managementKey?,
76
- * managementPrincipalId? }`): the Project's, or one the nylorun commands keep in the Host root.
77
- * Undefined when absent or unreadable.
51
+ * A credentials file (format 0 or 1): the Project's, or one the nylorun commands keep in the
52
+ * Host root. Undefined when absent or unreadable, so `start` replaces it.
78
53
  */
79
54
  export async function readCredentialsFile(path) {
55
+ let value;
80
56
  try {
81
- const value = JSON.parse(await readFile(path, "utf8"));
82
- if (typeof value.applicationKey !== "string" || typeof value.principalId !== "string")
83
- return undefined;
84
- return {
85
- applicationKey: value.applicationKey,
86
- principalId: value.principalId,
87
- ...(typeof value.managementKey === "string" && typeof value.managementPrincipalId === "string"
88
- ? { management: { key: value.managementKey, principalId: value.managementPrincipalId } }
89
- : {}),
90
- };
57
+ value = readCredentials(path);
91
58
  }
92
59
  catch {
93
60
  return undefined;
94
61
  }
62
+ if (!value)
63
+ return undefined;
64
+ return {
65
+ applicationKey: value.applicationKey,
66
+ principalId: value.principalId,
67
+ ...(value.managementKey && value.managementPrincipalId
68
+ ? { management: { key: value.managementKey, principalId: value.managementPrincipalId } }
69
+ : {}),
70
+ };
95
71
  }
96
72
  /** `.nylorun/credentials.json` (format 1, mode 0600). */
97
73
  export async function writeProjectCredentials(projectRoot, credentials) {
98
74
  await ensureProjectDir(projectRoot);
99
- await writeCredentialsFile(credentialsPath(projectRoot), credentials);
75
+ await writeCredentialsFile(projectCredentialsPath(projectRoot), credentials);
100
76
  }
101
77
  /** A credentials file (format 1), written atomically with mode 0600. */
102
78
  export async function writeCredentialsFile(path, credentials) {
@@ -2,9 +2,9 @@ import { existsSync } from "node:fs";
2
2
  import { mkdir, readFile, rm } from "node:fs/promises";
3
3
  import { basename, resolve } from "node:path";
4
4
  import { compareVersions } from "@nylorun/core/compatibility";
5
+ import { findProjectRoot } from "@nylorun/core/project";
5
6
  import { CliError } from "../errors.js";
6
7
  import { credentialsPath, readCredentialsFile, readProjectCredentials, readProjectLink, writeProjectCredentials, writeProjectLink, } from "../project/link.js";
7
- import { findProjectRoot } from "../project/root.js";
8
8
  import { seedTenant } from "../project/seed.js";
9
9
  import { readTelemetry, STUDIO_ANALYTICS_ID, TELEMETRY_NOTICE, telemetryDecision, writeTelemetry, } from "../telemetry.js";
10
10
  import { dockerPreflight, formatBytes, parseComposePs, tenantMemory, } from "./docker.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nylorun",
3
- "version": "0.12.0-beta",
3
+ "version": "0.12.1-beta",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Set up and run local Nylorun Tenants (Runtime and Studio) with Docker Compose",
@@ -30,7 +30,7 @@
30
30
  "prepack": "npm run build"
31
31
  },
32
32
  "dependencies": {
33
- "@nylorun/core": "0.17.0-beta"
33
+ "@nylorun/core": "0.18.0-beta"
34
34
  },
35
35
  "devDependencies": {
36
36
  "typescript": "npm:@typescript/typescript6@^6.0.2",
@@ -41,7 +41,7 @@
41
41
  "nylorun": "dist/cli.js"
42
42
  },
43
43
  "nylorun": {
44
- "runtime": "0.21.0-beta",
45
- "studio": "0.23.0-beta"
44
+ "runtime": "0.21.1-beta",
45
+ "studio": "0.23.1-beta"
46
46
  }
47
47
  }
package/dist/home.d.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`. Compose
3
- * bind-mounts it into the Runtime and Studio containers, and `@nylorun/admin`
4
- * reads `host.json` and the admin key from it.
5
- */
6
- export declare function resolveHome(home?: string, env?: Readonly<Record<string, string | undefined>>): string;
package/dist/home.js DELETED
@@ -1,15 +0,0 @@
1
- import { homedir } from "node:os";
2
- import { join, resolve } from "node:path";
3
- /**
4
- * The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`. Compose
5
- * bind-mounts it into the Runtime and Studio containers, and `@nylorun/admin`
6
- * reads `host.json` and the admin key from it.
7
- */
8
- export function resolveHome(home, env = process.env) {
9
- if (home !== undefined && home.trim() !== "")
10
- return resolve(home);
11
- const fromEnv = env.NYLORUN_HOME?.trim();
12
- if (fromEnv)
13
- return resolve(fromEnv);
14
- return resolve(join(homedir(), ".nylorun"));
15
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * The nearest `.nylorun` wins so an initialised Project keeps working from a
3
- * subdirectory; otherwise the nearest package.json defines the Project. The
4
- * walk stops at the home directory because `~/.nylorun` is the Host root, never
5
- * a Project root.
6
- */
7
- export declare function findProjectRoot(cwd?: string): string | undefined;
@@ -1,44 +0,0 @@
1
- import { existsSync, realpathSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { dirname, join, parse, resolve } from "node:path";
4
- /**
5
- * The nearest `.nylorun` wins so an initialised Project keeps working from a
6
- * subdirectory; otherwise the nearest package.json defines the Project. The
7
- * walk stops at the home directory because `~/.nylorun` is the Host root, never
8
- * a Project root.
9
- */
10
- export function findProjectRoot(cwd = process.cwd()) {
11
- const stop = (() => {
12
- try {
13
- return realpathSync(homedir());
14
- }
15
- catch {
16
- return homedir();
17
- }
18
- })();
19
- let directory = resolve(cwd);
20
- try {
21
- directory = realpathSync(directory);
22
- }
23
- catch {
24
- /* unresolvable cwd falls through */
25
- }
26
- const root = parse(directory).root;
27
- let fallback;
28
- for (;;) {
29
- // The home directory is never a Project, but a package.json below it is.
30
- if (directory === stop)
31
- return fallback;
32
- if (existsSync(join(directory, ".nylorun")))
33
- return directory;
34
- if (!fallback && existsSync(join(directory, "package.json")))
35
- fallback = directory;
36
- if (directory === root)
37
- break;
38
- const parent = dirname(directory);
39
- if (parent === directory)
40
- break;
41
- directory = parent;
42
- }
43
- return fallback;
44
- }