@helyx/cli 0.3.0 → 0.3.1
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 +6 -0
- package/README.md +1 -1
- package/dist/self-host/command.d.ts +7 -2
- package/dist/self-host/command.js +7 -5
- package/dist/self-host/update.js +52 -10
- package/package.json +1 -1
- package/self-host-catalogue.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9e290e1: Load the current reviewed self-host catalogue from the fixed Helyx API endpoint when generating a downloaded starter project, allowing compatible module-only releases without republishing the CLI. Catalogue requests now reject redirects, non-JSON responses, oversized bodies, invalid schemas and unavailable or stale catalogue data.
|
|
8
|
+
|
|
3
9
|
## 0.3.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ helyx self-host update --confirm
|
|
|
14
14
|
|
|
15
15
|
`setup` safely creates `.env` from a generated starter's `.env.example`, never overwrites existing configuration and reports whether Docker Compose is available. Direct Node.js operation remains fully supported with a local or hosted PostgreSQL database. `start` loads local configuration without overriding hosting-platform variables and performs the production bot bootstrap, including database and installed-module migrations. `migrate` applies only core migrations and exits. `doctor` validates the complete bot environment, PostgreSQL connectivity, immutable core migration history and configured module package metadata without logging in to Discord or modifying the database.
|
|
16
16
|
|
|
17
|
-
`self-host init`
|
|
17
|
+
`self-host init` retrieves the current reviewed catalogue from the fixed Helyx API endpoint, validates a downloaded build manifest against it, creates a new starter-project directory, pins the runtime and selected official modules, generates a lockfile with lifecycle scripts disabled, and writes checksums. The request has strict timeout, response-size, JSON-schema and official-package checks; no arbitrary catalogue URL or stale bundled fallback is accepted. Add `--install` only when the dependencies should also be installed locally. Unknown, unpublished, duplicated, stale or modified package selections fail closed.
|
|
18
18
|
|
|
19
19
|
`self-host update --check` reads the current project and the reviewed catalogue from `api.helyx.gg`, then reports the complete compatible release-set change without writing files. `--confirm` backs up the managed metadata under `.helyx/backups`, updates exact core, CLI and selected live-module versions together, refreshes and validates the lockfile with lifecycle scripts disabled, and restores the original metadata if generation fails. Run `npm ci` and `npm run doctor` after applying an update. The updater never changes `.env` or customer database data.
|
|
20
20
|
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { SelfHostCatalogue } from "./catalogue.js";
|
|
2
|
+
import { generateSelfHostProject, type GeneratedSelfHostProject } from "./project-generator.js";
|
|
2
3
|
import { type SelfHostUpdatePlan } from "./update.js";
|
|
3
4
|
export interface SelfHostInitArguments {
|
|
4
5
|
manifestPath: string;
|
|
5
6
|
outputPath: string;
|
|
6
7
|
install: boolean;
|
|
7
8
|
}
|
|
8
|
-
export
|
|
9
|
+
export interface SelfHostCommandDependencies {
|
|
10
|
+
catalogueLoader?: () => Promise<SelfHostCatalogue>;
|
|
11
|
+
projectGenerator?: typeof generateSelfHostProject;
|
|
12
|
+
}
|
|
13
|
+
export declare function runSelfHostCommand(arguments_: readonly string[], dependencies?: SelfHostCommandDependencies): Promise<GeneratedSelfHostProject | SelfHostUpdatePlan>;
|
|
9
14
|
export interface SelfHostUpdateArguments {
|
|
10
15
|
projectPath: string;
|
|
11
16
|
check: boolean;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { readFile, stat } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { loadBundledSelfHostCatalogue } from "./catalogue.js";
|
|
4
3
|
import { generateSelfHostProject, } from "./project-generator.js";
|
|
5
|
-
import { updateSelfHostProject } from "./update.js";
|
|
4
|
+
import { loadCurrentSelfHostCatalogue, updateSelfHostProject, } from "./update.js";
|
|
6
5
|
const maximumManifestBytes = 16 * 1_024;
|
|
7
|
-
export async function runSelfHostCommand(arguments_) {
|
|
6
|
+
export async function runSelfHostCommand(arguments_, dependencies = {}) {
|
|
8
7
|
const [subcommand, ...rest] = arguments_;
|
|
9
8
|
if (subcommand === "update") {
|
|
10
9
|
const parsed = parseSelfHostUpdateArguments(rest);
|
|
11
10
|
const plan = await updateSelfHostProject({
|
|
12
11
|
projectDirectory: parsed.projectPath,
|
|
13
12
|
apply: parsed.confirm,
|
|
13
|
+
...(dependencies.catalogueLoader
|
|
14
|
+
? { catalogueLoader: dependencies.catalogueLoader }
|
|
15
|
+
: {}),
|
|
14
16
|
});
|
|
15
17
|
printUpdatePlan(plan);
|
|
16
18
|
return plan;
|
|
@@ -33,8 +35,8 @@ export async function runSelfHostCommand(arguments_) {
|
|
|
33
35
|
cause: error,
|
|
34
36
|
});
|
|
35
37
|
}
|
|
36
|
-
const catalogue = await
|
|
37
|
-
const generated = await generateSelfHostProject({
|
|
38
|
+
const catalogue = await (dependencies.catalogueLoader ?? loadCurrentSelfHostCatalogue)();
|
|
39
|
+
const generated = await (dependencies.projectGenerator ?? generateSelfHostProject)({
|
|
38
40
|
catalogue,
|
|
39
41
|
manifest,
|
|
40
42
|
targetDirectory: parsed.outputPath,
|
package/dist/self-host/update.js
CHANGED
|
@@ -6,6 +6,8 @@ import { parse, resolve } from "node:path";
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { parseSelfHostCatalogue } from "./catalogue.js";
|
|
8
8
|
export const DEFAULT_SELF_HOST_CATALOGUE_URL = "https://api.helyx.gg/self-host/catalogue";
|
|
9
|
+
const maximumCatalogueBytes = 512 * 1_024;
|
|
10
|
+
const catalogueTimeoutMilliseconds = 15_000;
|
|
9
11
|
const packageName = z.string().regex(/^@helyx\/[a-z0-9][a-z0-9-]*$/u);
|
|
10
12
|
const modulePackage = z.string().regex(/^@helyx\/module-[a-z0-9][a-z0-9-]*$/u);
|
|
11
13
|
const exactVersion = z
|
|
@@ -100,34 +102,74 @@ export async function loadCurrentSelfHostCatalogue(fetcher = fetch) {
|
|
|
100
102
|
try {
|
|
101
103
|
response = await fetcher(DEFAULT_SELF_HOST_CATALOGUE_URL, {
|
|
102
104
|
headers: { Accept: "application/json" },
|
|
103
|
-
|
|
105
|
+
redirect: "error",
|
|
106
|
+
signal: AbortSignal.timeout(catalogueTimeoutMilliseconds),
|
|
104
107
|
});
|
|
105
108
|
}
|
|
106
109
|
catch (error) {
|
|
107
|
-
throw new Error("The reviewed Helyx
|
|
110
|
+
throw new Error("The reviewed Helyx self-host catalogue is unavailable", {
|
|
108
111
|
cause: error,
|
|
109
112
|
});
|
|
110
113
|
}
|
|
111
114
|
if (!response.ok) {
|
|
112
|
-
throw new Error(`The reviewed Helyx
|
|
115
|
+
throw new Error(`The reviewed Helyx self-host catalogue returned HTTP ${response.status}`);
|
|
113
116
|
}
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
-
throw new Error("The reviewed Helyx
|
|
117
|
+
const contentType = response.headers.get("content-type")?.toLowerCase();
|
|
118
|
+
if (!contentType?.startsWith("application/json")) {
|
|
119
|
+
throw new Error("The reviewed Helyx self-host catalogue did not return JSON");
|
|
117
120
|
}
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
+
const declaredLengthHeader = response.headers.get("content-length");
|
|
122
|
+
if (declaredLengthHeader !== null) {
|
|
123
|
+
const declaredLength = Number(declaredLengthHeader);
|
|
124
|
+
if (!Number.isSafeInteger(declaredLength) ||
|
|
125
|
+
declaredLength < 0 ||
|
|
126
|
+
declaredLength > maximumCatalogueBytes) {
|
|
127
|
+
throw new Error("The reviewed Helyx self-host catalogue had an invalid size");
|
|
128
|
+
}
|
|
121
129
|
}
|
|
130
|
+
const text = await readBoundedCatalogueBody(response);
|
|
122
131
|
try {
|
|
123
132
|
return parseSelfHostCatalogue(JSON.parse(text));
|
|
124
133
|
}
|
|
125
134
|
catch (error) {
|
|
126
|
-
throw new Error("The reviewed Helyx
|
|
135
|
+
throw new Error("The reviewed Helyx self-host catalogue was invalid", {
|
|
127
136
|
cause: error,
|
|
128
137
|
});
|
|
129
138
|
}
|
|
130
139
|
}
|
|
140
|
+
async function readBoundedCatalogueBody(response) {
|
|
141
|
+
if (!response.body) {
|
|
142
|
+
throw new Error("The reviewed Helyx self-host catalogue was empty");
|
|
143
|
+
}
|
|
144
|
+
const reader = response.body.getReader();
|
|
145
|
+
const chunks = [];
|
|
146
|
+
let totalBytes = 0;
|
|
147
|
+
try {
|
|
148
|
+
while (true) {
|
|
149
|
+
const { done, value } = await reader.read();
|
|
150
|
+
if (done)
|
|
151
|
+
break;
|
|
152
|
+
totalBytes += value.byteLength;
|
|
153
|
+
if (totalBytes > maximumCatalogueBytes) {
|
|
154
|
+
throw new Error("The reviewed Helyx self-host catalogue was too large");
|
|
155
|
+
}
|
|
156
|
+
chunks.push(value);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
reader.releaseLock();
|
|
161
|
+
}
|
|
162
|
+
if (totalBytes === 0) {
|
|
163
|
+
throw new Error("The reviewed Helyx self-host catalogue was empty");
|
|
164
|
+
}
|
|
165
|
+
const bytes = new Uint8Array(totalBytes);
|
|
166
|
+
let offset = 0;
|
|
167
|
+
for (const chunk of chunks) {
|
|
168
|
+
bytes.set(chunk, offset);
|
|
169
|
+
offset += chunk.byteLength;
|
|
170
|
+
}
|
|
171
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
172
|
+
}
|
|
131
173
|
function targetHelyxDependencies(catalogue, selection) {
|
|
132
174
|
if (catalogue.core.availability !== "published" ||
|
|
133
175
|
catalogue.generator.availability !== "published") {
|
package/package.json
CHANGED
package/self-host-catalogue.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"catalogueVersion":
|
|
3
|
+
"catalogueVersion": 12,
|
|
4
4
|
"core": {
|
|
5
5
|
"package": "@helyx/bot",
|
|
6
6
|
"version": "0.2.2",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"generator": {
|
|
10
10
|
"package": "@helyx/cli",
|
|
11
|
-
"version": "0.3.
|
|
11
|
+
"version": "0.3.1",
|
|
12
12
|
"command": "helyx",
|
|
13
13
|
"availability": "published"
|
|
14
14
|
},
|