@helyx/cli 1.2.2 → 1.4.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.
@@ -4,6 +4,7 @@ import { mkdir, readFile, readdir, rm, stat, writeFile, } from "node:fs/promises
4
4
  import { dirname, parse, resolve } from "node:path";
5
5
  import { isSelfHostModuleCustomerSelectable, } from "./catalogue.js";
6
6
  import { parseSelfHostBuildManifest, } from "./manifest.js";
7
+ import { databaseAdaptersForCatalogue, } from "./database-adapters.js";
7
8
  const generatedFileNames = [
8
9
  ".env.example",
9
10
  ".gitignore",
@@ -16,6 +17,7 @@ const generatedFileNames = [
16
17
  export async function generateSelfHostProject(options) {
17
18
  const manifest = parseSelfHostBuildManifest(options.manifest, options.catalogue);
18
19
  const targetDirectory = resolve(options.targetDirectory);
20
+ const databaseAdapters = options.databaseAdapters ?? databaseAdaptersForCatalogue(options.catalogue);
19
21
  const signal = options.signal ?? AbortSignal.timeout(120_000);
20
22
  signal.throwIfAborted();
21
23
  assertSafeTargetDirectory(targetDirectory);
@@ -24,7 +26,7 @@ export async function generateSelfHostProject(options) {
24
26
  try {
25
27
  await mkdir(targetDirectory);
26
28
  created = true;
27
- await writeGeneratedFiles(targetDirectory, manifest, options.catalogue);
29
+ await writeGeneratedFiles(targetDirectory, manifest, options.catalogue, databaseAdapters);
28
30
  signal.throwIfAborted();
29
31
  const runner = options.commandRunner ?? runNpmCommand;
30
32
  await runner([
@@ -35,7 +37,7 @@ export async function generateSelfHostProject(options) {
35
37
  "--no-fund",
36
38
  ], targetDirectory, signal);
37
39
  signal.throwIfAborted();
38
- await validateGeneratedLockfile(targetDirectory, manifest);
40
+ await validateGeneratedLockfile(targetDirectory, manifest, databaseAdapters);
39
41
  signal.throwIfAborted();
40
42
  if (options.install) {
41
43
  await runner(["ci", "--no-audit", "--no-fund"], targetDirectory, signal);
@@ -56,10 +58,14 @@ export async function generateSelfHostProject(options) {
56
58
  throw error;
57
59
  }
58
60
  }
59
- async function writeGeneratedFiles(targetDirectory, manifest, catalogue) {
61
+ async function writeGeneratedFiles(targetDirectory, manifest, catalogue, databaseAdapters) {
62
+ const databaseEngine = "databaseEngine" in manifest
63
+ ? (manifest.databaseEngine ?? "postgresql")
64
+ : "postgresql";
60
65
  const dependencyEntries = [
61
66
  [manifest.core.package, manifest.core.version],
62
67
  [manifest.generator.package, manifest.generator.version],
68
+ ...databaseAdapters.map((adapter) => [adapter.package, adapter.version]),
63
69
  ...manifest.modules.map((module) => [module.package, module.version]),
64
70
  ];
65
71
  dependencyEntries.sort(([left], [right]) => left.localeCompare(right, "en"));
@@ -85,20 +91,36 @@ async function writeGeneratedFiles(targetDirectory, manifest, catalogue) {
85
91
  const moduleCatalogue = {
86
92
  schemaVersion: 1,
87
93
  packages: manifest.modules.map((module) => module.package),
94
+ ...(databaseEngine === "mysql" ? { databaseEngine } : {}),
88
95
  };
89
96
  await writeFile(resolve(targetDirectory, "package.json"), formatJson(packageJson), "utf8");
90
97
  await writeFile(resolve(targetDirectory, "helyx.modules.json"), formatJson(moduleCatalogue), "utf8");
91
98
  for (const fileName of generatedFileNames) {
92
- const template = await readFile(templateUrl(fileName), "utf8");
99
+ const template = await readFile(fileName === "compose.yaml" && databaseEngine === "mysql"
100
+ ? mysqlComposeTemplateUrl()
101
+ : templateUrl(fileName), "utf8");
102
+ const rendered = fileName === ".env.example"
103
+ ? renderEnvironmentExample(template, databaseEngine)
104
+ : fileName === "README.md"
105
+ ? renderReadme(template, manifest, catalogue, databaseEngine)
106
+ : template;
93
107
  if (fileName === ".env.example")
94
- validateEnvironmentTemplate(template);
95
- const content = fileName === "README.md"
96
- ? renderReadme(template, manifest, catalogue)
97
- : normalizeCrLf(template);
108
+ validateEnvironmentTemplate(rendered, databaseEngine);
109
+ const content = normalizeCrLf(rendered);
98
110
  await writeFile(resolve(targetDirectory, fileName), content, "utf8");
99
111
  }
100
112
  }
101
- function renderReadme(template, manifest, catalogue) {
113
+ function renderEnvironmentExample(template, databaseEngine) {
114
+ if (databaseEngine === "postgresql")
115
+ return template;
116
+ return template
117
+ .replaceAll("\r\n", "\n")
118
+ .replace("# Docker: keep the URL. Direct Node.js/managed hosting: use your provider URL.\nDATABASE_ENGINE=postgresql\nDATABASE_URL=postgresql://database:5432/helyx", "# Use the MySQL-compatible database URL supplied by your provider.\n# The included Compose file runs only the bot; it never starts a second database.\nDATABASE_ENGINE=mysql\nDATABASE_URL=mysql://user:password@host:3306/helyx")
119
+ .replace(/# Included Docker database[^\n]*\nPGUSER=helyx\nPGPASSWORD=replace-with-a-strong-password\nPOSTGRES_DB=helyx\nPOSTGRES_USER=helyx\nPOSTGRES_PASSWORD=replace-with-a-strong-password\n\n/u, "")
120
+ .replace("HELYX_SHARD_MODE=off\n", "# MySQL-compatible self-hosting currently supports only this unsharded mode.\nHELYX_SHARD_MODE=off\n")
121
+ .replace("DATABASE_SSL=disable", "DATABASE_SSL=require");
122
+ }
123
+ function renderReadme(template, manifest, catalogue, databaseEngine) {
102
124
  const modulesById = new Map(catalogue.modules.map((module) => [module.id, module]));
103
125
  const selected = manifest.modules.length
104
126
  ? manifest.modules
@@ -111,7 +133,19 @@ function renderReadme(template, manifest, catalogue) {
111
133
  .filter((line) => line !== null)
112
134
  .join("\n")
113
135
  : "- No feature modules selected. This is a core-only installation.";
114
- return normalizeCrLf(template.replace("{{SELECTED_MODULES}}", selected));
136
+ let rendered = template
137
+ .replaceAll("\r\n", "\n")
138
+ .replace("{{SELECTED_MODULES}}", selected);
139
+ if (databaseEngine === "mysql") {
140
+ rendered = rendered
141
+ .replace("3. Edit `.env`, replace every placeholder, set `DATABASE_ENGINE` to `postgresql` or `mysql`, and set the matching `DATABASE_URL`. Omitting `DATABASE_ENGINE` selects PostgreSQL.", "3. Edit `.env`, replace every placeholder, keep `DATABASE_ENGINE=mysql` and `HELYX_SHARD_MODE=off`, and set `DATABASE_URL` to the MySQL-compatible URL supplied by your provider. Percent-encode special characters in URL credentials.")
142
+ .replace("Use this path when Docker with Compose support is available. The included configuration runs both Helyx and PostgreSQL 17.", "Use this path when Docker with Compose support is available. The included configuration runs only Helyx; it connects to your existing MySQL-compatible database and does not create a second database service.")
143
+ .replace("2. Edit `.env` and replace all placeholder credentials and passwords.\n3. Keep `DATABASE_ENGINE=postgresql` with the supplied internal `DATABASE_URL` and `DATABASE_SSL=disable`.\n4. Run `docker compose up --build -d`.\n5. Review startup with `docker compose logs -f bot`.\n6. Stop services with `docker compose down`. Do not add `--volumes` unless you deliberately intend to delete the database volume.", "2. Edit `.env` and replace all placeholder credentials. Keep `DATABASE_ENGINE=mysql` and supply your provider's reachable `DATABASE_URL` and required `DATABASE_SSL` setting.\n3. Run `docker compose up --build -d`.\n4. Review startup with `docker compose logs -f bot`.\n5. Stop the bot with `docker compose down`. Your external database is not managed by this Compose file.");
144
+ }
145
+ return rendered;
146
+ }
147
+ function mysqlComposeTemplateUrl() {
148
+ return new URL("../../templates/self-host/compose.mysql.yaml", import.meta.url);
115
149
  }
116
150
  function templateUrl(fileName) {
117
151
  const templateName = fileName === ".npmrc"
@@ -130,19 +164,26 @@ function normalizeCrLf(value) {
130
164
  .replaceAll("\r", "\n")
131
165
  .replaceAll("\n", "\r\n");
132
166
  }
133
- function validateEnvironmentTemplate(template) {
167
+ function validateEnvironmentTemplate(template, databaseEngine) {
134
168
  const lines = new Set(template
135
169
  .replaceAll("\r\n", "\n")
136
170
  .split("\n")
137
171
  .map((line) => line.trim()));
138
172
  for (const [key, definition] of Object.entries(selfHostEnvironmentContract)) {
139
- const expected = `${definition.optional ? "# " : ""}${key}=${definition.value}`;
173
+ const value = key === "DATABASE_ENGINE"
174
+ ? databaseEngine
175
+ : key === "DATABASE_URL" && databaseEngine === "mysql"
176
+ ? "mysql://user:password@host:3306/helyx"
177
+ : key === "DATABASE_SSL" && databaseEngine === "mysql"
178
+ ? "require"
179
+ : definition.value;
180
+ const expected = `${definition.optional ? "# " : ""}${key}=${value}`;
140
181
  if (!lines.has(expected)) {
141
182
  throw new Error(`Self-host environment template does not match the bot contract: ${key}`);
142
183
  }
143
184
  }
144
185
  }
145
- async function validateGeneratedLockfile(targetDirectory, manifest) {
186
+ async function validateGeneratedLockfile(targetDirectory, manifest, databaseAdapters) {
146
187
  const lockfilePath = resolve(targetDirectory, "package-lock.json");
147
188
  const lockfile = JSON.parse(await readFile(lockfilePath, "utf8"));
148
189
  if (!isRecord(lockfile) || !isRecord(lockfile.packages)) {
@@ -159,6 +200,7 @@ async function validateGeneratedLockfile(targetDirectory, manifest) {
159
200
  const expected = new Map([
160
201
  [manifest.core.package, manifest.core.version],
161
202
  [manifest.generator.package, manifest.generator.version],
203
+ ...databaseAdapters.map((adapter) => [adapter.package, adapter.version]),
162
204
  ...manifest.modules.map((module) => [module.package, module.version]),
163
205
  ]);
164
206
  if (Object.keys(lockedDependencies).length !== expected.size ||
@@ -265,14 +307,17 @@ function isRecord(value) {
265
307
  // This compile-time map intentionally stays adjacent to the generator. Adding a
266
308
  // bot environment field makes the generated contract fail to compile until the
267
309
  // self-host example receives an explicit safe value or omission decision.
268
- // Support service authentication, staff delivery, and Verification remain
269
- // hosted-only and are deliberately excluded from generated self-host projects.
310
+ // Request My Data, support service authentication, staff delivery, and
311
+ // Verification remain hosted-only and are deliberately excluded from generated
312
+ // self-host projects.
270
313
  export const selfHostEnvironmentContract = {
314
+ DATABASE_ENGINE: { value: "postgresql", optional: false },
271
315
  DATABASE_URL: {
272
316
  value: "postgresql://database:5432/helyx",
273
317
  optional: false,
274
318
  },
275
319
  DATABASE_SSL: { value: "disable", optional: false },
320
+ HELYX_DATABASE_STARTUP_MODE: { value: "apply", optional: true },
276
321
  HELYX_RUNTIME_PROFILE: { value: "self-hosted", optional: false },
277
322
  HELYX_DEPLOYMENT_ENVIRONMENT: { value: "self-hosted", optional: false },
278
323
  DISCORD_TOKEN: { value: "replace-me", optional: false },
@@ -324,16 +369,7 @@ export const selfHostEnvironmentContract = {
324
369
  HELYX_GUILD_COMMAND_RELEASE_ID: { value: "", optional: true },
325
370
  HELYX_GLOBAL_COMMAND_MODE: { value: "legacy", optional: false },
326
371
  HELYX_GUILD_COMMAND_WRITE_GUILD_IDS: { value: "", optional: true },
327
- HELYX_PRIVACY_ENABLED: { value: "false", optional: false },
328
372
  HELYX_GUILD_MEMBERS_ENABLED: { value: "false", optional: false },
329
- HELYX_PRIVACY_EXECUTOR_DATABASE_URL: {
330
- value: "<dedicated-privacy-executor-postgresql-url>",
331
- optional: true,
332
- },
333
- HELYX_PRIVACY_EXECUTOR_DATABASE_SSL: {
334
- value: "disable",
335
- optional: true,
336
- },
337
373
  HELYX_CLOUD_CONNECT_ENABLED: { value: "true", optional: false },
338
374
  HELYX_CLOUD_ENROLMENT_TOKEN: {
339
375
  value: "replace-with-a-short-lived-enrolment-code",
@@ -2,14 +2,15 @@ import { type SelfHostCatalogue } from "./catalogue.js";
2
2
  export declare const DEFAULT_SELF_HOST_CATALOGUE_URL = "https://api.helyx.gg/self-host/catalogue";
3
3
  export interface SelfHostUpdateChange {
4
4
  package: string;
5
- currentVersion: string;
6
- targetVersion: string;
7
- direction: "upgrade" | "downgrade";
5
+ currentVersion: string | null;
6
+ targetVersion: string | null;
7
+ direction: "add" | "upgrade" | "downgrade" | "remove";
8
8
  }
9
9
  export interface SelfHostUpdatePlan {
10
10
  projectDirectory: string;
11
11
  catalogueVersion: number;
12
12
  changes: SelfHostUpdateChange[];
13
+ moduleSelectionChanged: boolean;
13
14
  upToDate: boolean;
14
15
  }
15
16
  export type SelfHostUpdateCommandRunner = (arguments_: readonly string[], workingDirectory: string) => Promise<void>;
@@ -4,7 +4,9 @@ import { spawn } from "node:child_process";
4
4
  import { copyFile, mkdir, readFile, readdir, rename, stat, writeFile, } from "node:fs/promises";
5
5
  import { parse, resolve } from "node:path";
6
6
  import { z } from "zod";
7
- import { parseSelfHostCatalogue } from "./catalogue.js";
7
+ import { isSelfHostModuleCustomerSelectable, parseSelfHostCatalogue, selfHostDatabaseEngineSchema, } from "./catalogue.js";
8
+ import { databaseAdaptersForCatalogue } from "./database-adapters.js";
9
+ import { createSelfHostBuildManifest } from "./manifest.js";
8
10
  export const DEFAULT_SELF_HOST_CATALOGUE_URL = "https://api.helyx.gg/self-host/catalogue";
9
11
  const maximumCatalogueBytes = 512 * 1_024;
10
12
  const catalogueTimeoutMilliseconds = 15_000;
@@ -24,7 +26,8 @@ const packageJsonSchema = z
24
26
  const moduleSelectionSchema = z
25
27
  .object({
26
28
  schemaVersion: z.literal(1),
27
- packages: z.array(modulePackage).max(30),
29
+ packages: z.array(modulePackage),
30
+ databaseEngine: selfHostDatabaseEngineSchema.optional(),
28
31
  })
29
32
  .strict()
30
33
  .superRefine((value, context) => {
@@ -53,14 +56,16 @@ export async function updateSelfHostProject(options = {}) {
53
56
  ? Promise.resolve(options.catalogue)
54
57
  : (options.catalogueLoader ?? loadCurrentSelfHostCatalogue)(),
55
58
  ]);
56
- const targetDependencies = targetHelyxDependencies(catalogue, selection);
57
- validateManagedDependencies(packageJson.dependencies, targetDependencies);
58
- const changes = collectChanges(packageJson.dependencies, targetDependencies);
59
+ const target = targetHelyxDependencies(catalogue, selection);
60
+ validateManagedDependencies(packageJson.dependencies, target.dependencies, selection.packages, target.addedDependencyPackages);
61
+ const changes = collectChanges(packageJson.dependencies, target.dependencies);
62
+ const selectionChanged = JSON.stringify(selection.packages) !== JSON.stringify(target.packages);
59
63
  const plan = {
60
64
  projectDirectory,
61
65
  catalogueVersion: catalogue.catalogueVersion,
62
66
  changes,
63
- upToDate: changes.length === 0,
67
+ moduleSelectionChanged: selectionChanged,
68
+ upToDate: changes.length === 0 && !selectionChanged,
64
69
  };
65
70
  if (!options.apply || plan.upToDate)
66
71
  return plan;
@@ -75,11 +80,16 @@ export async function updateSelfHostProject(options = {}) {
75
80
  update: "helyx self-host update --confirm && npm ci",
76
81
  },
77
82
  dependencies: {
78
- ...packageJson.dependencies,
79
- ...Object.fromEntries(targetDependencies),
83
+ ...Object.fromEntries(Object.entries(packageJson.dependencies).filter(([name]) => !name.startsWith("@helyx/"))),
84
+ ...Object.fromEntries(target.dependencies),
80
85
  },
81
86
  };
82
87
  await atomicWriteJson(resolve(projectDirectory, "package.json"), nextPackageJson);
88
+ if (selectionChanged)
89
+ await atomicWriteJson(resolve(projectDirectory, "helyx.modules.json"), {
90
+ ...selection,
91
+ packages: target.packages,
92
+ });
83
93
  const runner = options.commandRunner ?? runNpmCommand;
84
94
  await runner([
85
95
  "install",
@@ -88,7 +98,7 @@ export async function updateSelfHostProject(options = {}) {
88
98
  "--no-audit",
89
99
  "--no-fund",
90
100
  ], projectDirectory);
91
- await validateUpdatedLockfile(projectDirectory, targetDependencies);
101
+ await validateUpdatedLockfile(projectDirectory, target.dependencies);
92
102
  await writeChecksums(projectDirectory);
93
103
  return plan;
94
104
  }
@@ -185,41 +195,74 @@ function targetHelyxDependencies(catalogue, selection) {
185
195
  module.version === null) {
186
196
  throw new Error(`Selected module is not in the current reviewed free live release: ${selectedPackage}`);
187
197
  }
188
- return [module.package, module.version];
198
+ return module;
189
199
  });
190
- return new Map([
200
+ if (selection.databaseEngine === "mysql" && catalogue.schemaVersion !== 2) {
201
+ throw new Error("The reviewed self-host catalogue lacks MySQL compatibility metadata");
202
+ }
203
+ const modules = catalogue.schemaVersion === 2
204
+ ? createSelfHostBuildManifest(catalogue, selected
205
+ .filter(isSelfHostModuleCustomerSelectable)
206
+ .map(({ id }) => id), selection.databaseEngine ?? "postgresql").modules
207
+ : selected;
208
+ const dependencies = new Map([
191
209
  [catalogue.core.package, catalogue.core.version],
192
210
  [catalogue.generator.package, catalogue.generator.version],
193
- ...selected,
211
+ ...databaseAdaptersForCatalogue(catalogue).map((adapter) => [adapter.package, adapter.version]),
212
+ ...modules.map((module) => [module.package, module.version]),
194
213
  ]);
214
+ return {
215
+ dependencies,
216
+ packages: modules.map(({ package: name }) => name),
217
+ addedDependencyPackages: modules
218
+ .filter((module) => "moduleKind" in module &&
219
+ module.moduleKind === "internal_dependency" &&
220
+ !selection.packages.includes(module.package))
221
+ .map(({ package: name }) => name),
222
+ };
195
223
  }
196
- function validateManagedDependencies(current, target) {
224
+ function validateManagedDependencies(current, target, selectedPackages, addedDependencyPackages) {
197
225
  for (const [name, version] of Object.entries(current)) {
198
226
  if (!name.startsWith("@helyx/"))
199
227
  continue;
200
228
  packageName.parse(name);
201
229
  exactVersion.parse(version);
202
- if (!target.has(name)) {
230
+ if (!target.has(name) && !selectedPackages.includes(name)) {
203
231
  throw new Error(`Unexpected Helyx dependency is not controlled by helyx.modules.json: ${name}`);
204
232
  }
205
233
  }
206
234
  for (const name of target.keys()) {
207
- if (!(name in current)) {
235
+ if (!(name in current) &&
236
+ !addedDependencyPackages.includes(name) &&
237
+ name !== "@helyx/database" &&
238
+ name !== "@helyx/database-mysql") {
208
239
  throw new Error(`Generated project is missing Helyx dependency: ${name}`);
209
240
  }
210
241
  }
211
242
  }
212
243
  function collectChanges(current, target) {
213
- return [...target]
214
- .filter(([name, version]) => current[name] !== version)
215
- .map(([name, version]) => ({
216
- package: name,
217
- currentVersion: current[name],
218
- targetVersion: version,
219
- direction: semver.gt(version, current[name])
220
- ? "upgrade"
221
- : "downgrade",
222
- }))
244
+ const names = new Set([
245
+ ...target.keys(),
246
+ ...Object.keys(current).filter((name) => name.startsWith("@helyx/")),
247
+ ]);
248
+ return [...names]
249
+ .filter((name) => current[name] !== target.get(name))
250
+ .map((name) => {
251
+ const version = target.get(name) ?? null;
252
+ const currentVersion = current[name] ?? null;
253
+ return {
254
+ package: name,
255
+ currentVersion,
256
+ targetVersion: version,
257
+ direction: version === null
258
+ ? "remove"
259
+ : currentVersion === null
260
+ ? "add"
261
+ : semver.gt(version, currentVersion)
262
+ ? "upgrade"
263
+ : "downgrade",
264
+ };
265
+ })
223
266
  .sort((left, right) => left.package.localeCompare(right.package, "en"));
224
267
  }
225
268
  async function readProjectJson(projectDirectory) {
@@ -277,6 +320,10 @@ async function validateUpdatedLockfile(projectDirectory, target) {
277
320
  throw new Error(`Updated package-lock.json does not pin ${name}@${version}`);
278
321
  }
279
322
  }
323
+ for (const name of Object.keys(root.dependencies)) {
324
+ if (name.startsWith("@helyx/") && !target.has(name))
325
+ throw new Error(`Updated package-lock.json retains ${name}`);
326
+ }
280
327
  }
281
328
  async function writeChecksums(projectDirectory) {
282
329
  const fileNames = (await readdir(projectDirectory))
package/dist/setup.d.ts CHANGED
@@ -7,6 +7,7 @@ export interface SetupSelfHostEnvironmentResult {
7
7
  created: boolean;
8
8
  dataEncryptionKeyCreated: boolean;
9
9
  dockerComposeAvailable: boolean;
10
+ databaseEngine: "postgresql" | "mysql";
10
11
  environmentPath: string;
11
12
  }
12
13
  export declare function setupSelfHostEnvironment(options?: SetupSelfHostEnvironmentOptions): Promise<SetupSelfHostEnvironmentResult>;
package/dist/setup.js CHANGED
@@ -12,6 +12,11 @@ export async function setupSelfHostEnvironment(options = {}) {
12
12
  await assertGeneratedStarter(cwd);
13
13
  const examplePath = resolve(cwd, ".env.example");
14
14
  const environmentPath = resolve(cwd, ".env");
15
+ const example = parseEnv(await readFile(examplePath, "utf8"));
16
+ const databaseEngine = example.DATABASE_ENGINE ?? "postgresql";
17
+ if (databaseEngine !== "postgresql" && databaseEngine !== "mysql") {
18
+ throw new Error("The starter has an unsupported DATABASE_ENGINE value");
19
+ }
15
20
  let created = false;
16
21
  try {
17
22
  await copyFile(examplePath, environmentPath, constants.COPYFILE_EXCL);
@@ -27,6 +32,7 @@ export async function setupSelfHostEnvironment(options = {}) {
27
32
  created,
28
33
  dataEncryptionKeyCreated,
29
34
  dockerComposeAvailable: await (options.detectDockerCompose ?? detectDockerCompose)(),
35
+ databaseEngine,
30
36
  environmentPath,
31
37
  };
32
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helyx/cli",
3
- "version": "1.2.2",
3
+ "version": "1.4.0",
4
4
  "description": "Command-line tools for running and generating self-hosted Helyx deployments.",
5
5
  "keywords": [
6
6
  "helyx",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "publishConfig": {
27
27
  "access": "public",
28
- "provenance": true
28
+ "provenance": false
29
29
  },
30
30
  "type": "module",
31
31
  "files": [
@@ -52,12 +52,15 @@
52
52
  "build": "tsc -b"
53
53
  },
54
54
  "dependencies": {
55
- "@helyx/bot": ">=1.0.0 <2.0.0",
56
- "@helyx/config": ">=1.0.0 <2.0.0",
57
- "@helyx/database": ">=2.0.0 <3.0.0",
55
+ "@helyx/bot": ">=1.4.0 <2.0.0",
56
+ "@helyx/config": ">=1.4.0 <2.0.0",
57
+ "@helyx/database": ">=2.4.0 <3.0.0",
58
58
  "semver": "7.8.5",
59
59
  "zod": "4.4.3"
60
60
  },
61
+ "optionalDependencies": {
62
+ "@helyx/database-mysql": ">=0.2.0 <0.3.0"
63
+ },
61
64
  "devDependencies": {
62
65
  "@types/semver": "7.7.1"
63
66
  }