everything-dev 1.27.0 → 1.28.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.
Files changed (104) hide show
  1. package/dist/cli/infra.cjs +1 -1
  2. package/dist/cli/infra.mjs +1 -1
  3. package/dist/cli/init.cjs +7 -9
  4. package/dist/cli/init.cjs.map +1 -1
  5. package/dist/cli/init.d.cts +1 -1
  6. package/dist/cli/init.d.cts.map +1 -1
  7. package/dist/cli/init.d.mts +1 -1
  8. package/dist/cli/init.d.mts.map +1 -1
  9. package/dist/cli/init.mjs +7 -9
  10. package/dist/cli/init.mjs.map +1 -1
  11. package/dist/cli/prompts.cjs +28 -24
  12. package/dist/cli/prompts.cjs.map +1 -1
  13. package/dist/cli/prompts.mjs +27 -24
  14. package/dist/cli/prompts.mjs.map +1 -1
  15. package/dist/cli/sync.cjs +4 -1
  16. package/dist/cli/sync.cjs.map +1 -1
  17. package/dist/cli/sync.mjs +4 -1
  18. package/dist/cli/sync.mjs.map +1 -1
  19. package/dist/cli.cjs +187 -12
  20. package/dist/cli.cjs.map +1 -1
  21. package/dist/cli.mjs +186 -11
  22. package/dist/cli.mjs.map +1 -1
  23. package/dist/contract.cjs +1 -1
  24. package/dist/contract.cjs.map +1 -1
  25. package/dist/contract.d.cts +38 -34
  26. package/dist/contract.d.cts.map +1 -1
  27. package/dist/contract.d.mts +38 -34
  28. package/dist/contract.d.mts.map +1 -1
  29. package/dist/contract.mjs +1 -0
  30. package/dist/contract.mjs.map +1 -1
  31. package/dist/dev-session.cjs +0 -1
  32. package/dist/dev-session.mjs +1 -1
  33. package/dist/index.cjs +0 -2
  34. package/dist/index.d.cts +2 -2
  35. package/dist/index.d.mts +2 -2
  36. package/dist/index.mjs +0 -1
  37. package/dist/near-cli.cjs +1 -1
  38. package/dist/near-cli.mjs +1 -1
  39. package/dist/orchestrator.cjs +1 -1
  40. package/dist/orchestrator.mjs +1 -1
  41. package/dist/plugin.cjs +163 -139
  42. package/dist/plugin.cjs.map +1 -1
  43. package/dist/plugin.d.cts +67 -34
  44. package/dist/plugin.d.cts.map +1 -1
  45. package/dist/plugin.d.mts +66 -34
  46. package/dist/plugin.d.mts.map +1 -1
  47. package/dist/plugin.mjs +153 -130
  48. package/dist/plugin.mjs.map +1 -1
  49. package/dist/service-descriptor.d.cts +34 -0
  50. package/dist/service-descriptor.d.cts.map +1 -0
  51. package/dist/service-descriptor.d.mts +36 -0
  52. package/dist/service-descriptor.d.mts.map +1 -0
  53. package/dist/types.d.cts +2 -2
  54. package/dist/types.d.mts +2 -2
  55. package/package.json +2 -2
  56. package/src/api-contract.ts +0 -623
  57. package/src/app.ts +0 -193
  58. package/src/cli/catalog.ts +0 -49
  59. package/src/cli/framework-version.ts +0 -61
  60. package/src/cli/help.ts +0 -13
  61. package/src/cli/infra.ts +0 -190
  62. package/src/cli/init.ts +0 -1145
  63. package/src/cli/parse.ts +0 -147
  64. package/src/cli/prompts.ts +0 -135
  65. package/src/cli/snapshot.ts +0 -46
  66. package/src/cli/status.ts +0 -99
  67. package/src/cli/sync.ts +0 -429
  68. package/src/cli/timing.ts +0 -63
  69. package/src/cli/upgrade.ts +0 -869
  70. package/src/cli.ts +0 -516
  71. package/src/components/dev-view.tsx +0 -352
  72. package/src/components/streaming-view.ts +0 -177
  73. package/src/config.ts +0 -893
  74. package/src/contract.meta.ts +0 -140
  75. package/src/contract.ts +0 -326
  76. package/src/dev-logs.ts +0 -92
  77. package/src/dev-session.ts +0 -283
  78. package/src/fastkv.ts +0 -181
  79. package/src/index.ts +0 -8
  80. package/src/integrity.ts +0 -138
  81. package/src/internal/manifest-normalizer.ts +0 -290
  82. package/src/merge.ts +0 -187
  83. package/src/mf.ts +0 -147
  84. package/src/near-cli.ts +0 -259
  85. package/src/network.ts +0 -3
  86. package/src/orchestrator.ts +0 -493
  87. package/src/plugin.ts +0 -1799
  88. package/src/sdk.ts +0 -14
  89. package/src/service-descriptor.ts +0 -281
  90. package/src/shared.ts +0 -249
  91. package/src/sidebar.ts +0 -140
  92. package/src/types.ts +0 -330
  93. package/src/ui/head.ts +0 -83
  94. package/src/ui/index.ts +0 -5
  95. package/src/ui/metadata.ts +0 -95
  96. package/src/ui/router.ts +0 -88
  97. package/src/ui/runtime.ts +0 -42
  98. package/src/ui/types.ts +0 -65
  99. package/src/utils/banner.ts +0 -21
  100. package/src/utils/linkify.ts +0 -11
  101. package/src/utils/path-match.ts +0 -16
  102. package/src/utils/run.ts +0 -31
  103. package/src/utils/save-config.ts +0 -20
  104. package/src/utils/theme.ts +0 -39
package/src/app.ts DELETED
@@ -1,193 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { createConnection } from "node:net";
3
- import { join } from "node:path";
4
- import {
5
- buildRuntimeConfig as configBuildRuntimeConfig,
6
- getProjectRoot,
7
- resolveLocalDevelopmentPath,
8
- } from "./config";
9
- import type { AppOrchestrator } from "./service-descriptor";
10
- import type { BosConfig, RuntimeConfig, RuntimePluginConfig } from "./types";
11
-
12
- export type { AppOrchestrator };
13
-
14
- const DEFAULT_HOST_PORT = 3000;
15
- const DEFAULT_API_PORT = 3001;
16
- const DEFAULT_AUTH_PORT = 3002;
17
- const DEFAULT_UI_PORT = 3003;
18
- const DEFAULT_PLUGIN_PORT_START = 3010;
19
-
20
- export function detectLocalPackages(
21
- bosConfig?: BosConfig,
22
- runtimeConfig?: RuntimeConfig,
23
- ): string[] {
24
- const packages: string[] = [];
25
- const configDir = getProjectRoot();
26
-
27
- const uiLocalPath =
28
- runtimeConfig?.ui.localPath ??
29
- resolveLocalDevelopmentPath(bosConfig?.app.ui.development, configDir);
30
- if (uiLocalPath && existsSync(join(uiLocalPath, "package.json"))) {
31
- packages.push("ui");
32
- }
33
-
34
- const apiLocalPath =
35
- runtimeConfig?.api.localPath ??
36
- resolveLocalDevelopmentPath(bosConfig?.app.api.development, configDir);
37
- if (apiLocalPath && existsSync(join(apiLocalPath, "package.json"))) {
38
- packages.push("api");
39
- }
40
-
41
- const hostLocalPath =
42
- runtimeConfig?.host?.localPath ??
43
- resolveLocalDevelopmentPath(bosConfig?.app.host.development, configDir);
44
- if (hostLocalPath && existsSync(join(hostLocalPath, "package.json"))) {
45
- packages.push("host");
46
- } else if (existsSync(join(configDir, "host", "package.json"))) {
47
- packages.push("host");
48
- }
49
-
50
- for (const [pluginId, pluginConfig] of Object.entries(runtimeConfig?.plugins ?? {})) {
51
- if (pluginConfig.localPath && existsSync(join(pluginConfig.localPath, "package.json"))) {
52
- packages.push(`plugin:${pluginId}`);
53
- }
54
- if (pluginConfig.ui?.localPath && existsSync(join(pluginConfig.ui.localPath, "package.json"))) {
55
- packages.push(`plugin-ui:${pluginId}`);
56
- }
57
- }
58
-
59
- const authLocalPath =
60
- runtimeConfig?.auth?.localPath ??
61
- resolveLocalDevelopmentPath(bosConfig?.app.auth?.development, configDir);
62
- if (authLocalPath && existsSync(join(authLocalPath, "package.json"))) {
63
- packages.push("auth");
64
- }
65
-
66
- return packages;
67
- }
68
-
69
- export function buildRuntimeConfig(
70
- bosConfig: BosConfig,
71
- options: {
72
- hostSource?: "local" | "remote";
73
- uiSource?: "local" | "remote";
74
- apiSource?: "local" | "remote";
75
- authSource?: "local" | "remote";
76
- proxy?: string;
77
- env?: "development" | "production";
78
- plugins?: Record<string, RuntimePluginConfig>;
79
- },
80
- ): RuntimeConfig {
81
- return configBuildRuntimeConfig(bosConfig, getProjectRoot(), options.env ?? "development", {
82
- hostSource: options.hostSource,
83
- uiSource: options.uiSource,
84
- apiSource: options.apiSource,
85
- authSource: options.authSource,
86
- proxy: options.proxy,
87
- plugins: options.plugins,
88
- });
89
- }
90
-
91
- function probeTcpOpen(port: number, timeoutMs = 250): Promise<boolean> {
92
- return new Promise((resolve) => {
93
- const socket = createConnection({ host: "127.0.0.1", port });
94
- const timer = setTimeout(() => {
95
- socket.destroy();
96
- resolve(false);
97
- }, timeoutMs);
98
-
99
- socket.once("connect", () => {
100
- clearTimeout(timer);
101
- socket.destroy();
102
- resolve(true);
103
- });
104
-
105
- socket.once("error", () => {
106
- clearTimeout(timer);
107
- resolve(false);
108
- });
109
- });
110
- }
111
-
112
- async function pickAvailablePort(preferred: number, usedPorts: Set<number>): Promise<number> {
113
- let port = preferred;
114
- while (usedPorts.has(port) || (await probeTcpOpen(port))) {
115
- port += 1;
116
- }
117
- usedPorts.add(port);
118
- return port;
119
- }
120
-
121
- function withLocalRuntimeUrl<
122
- T extends { url: string; entry: string; port?: number; localPath?: string },
123
- >(entry: T, port: number): T {
124
- const url = `http://localhost:${port}`;
125
- return {
126
- ...entry,
127
- url,
128
- entry: `${url}/mf-manifest.json`,
129
- port,
130
- };
131
- }
132
-
133
- export async function prepareDevelopmentRuntimeConfig(
134
- runtimeConfig: RuntimeConfig,
135
- options?: { hostPort?: number; ssr?: boolean },
136
- ): Promise<RuntimeConfig> {
137
- const usedPorts = new Set<number>();
138
- const hostPort = await pickAvailablePort(options?.hostPort ?? DEFAULT_HOST_PORT, usedPorts);
139
-
140
- const next: RuntimeConfig = {
141
- ...runtimeConfig,
142
- host: { ...runtimeConfig.host, url: `http://localhost:${hostPort}`, port: hostPort },
143
- ui: { ...runtimeConfig.ui },
144
- api: { ...runtimeConfig.api },
145
- auth: runtimeConfig.auth ? { ...runtimeConfig.auth } : undefined,
146
- plugins: runtimeConfig.plugins ? { ...runtimeConfig.plugins } : undefined,
147
- };
148
-
149
- if (next.api.source === "local" && next.api.localPath) {
150
- const apiPort = await pickAvailablePort(next.api.port ?? DEFAULT_API_PORT, usedPorts);
151
- next.api = withLocalRuntimeUrl(next.api, apiPort);
152
- }
153
-
154
- if (next.auth?.source === "local" && next.auth.localPath) {
155
- const authPort = await pickAvailablePort(next.auth.port ?? DEFAULT_AUTH_PORT, usedPorts);
156
- next.auth = withLocalRuntimeUrl(next.auth, authPort);
157
- }
158
-
159
- if (next.ui.source === "local" && next.ui.localPath) {
160
- const uiPort = await pickAvailablePort(next.ui.port ?? DEFAULT_UI_PORT, usedPorts);
161
- next.ui = withLocalRuntimeUrl(next.ui, uiPort);
162
- if (options?.ssr) {
163
- const ssrPort = await pickAvailablePort(uiPort + 1, usedPorts);
164
- next.ui.ssrUrl = `http://localhost:${ssrPort}`;
165
- } else {
166
- next.ui.ssrUrl = undefined;
167
- }
168
- }
169
-
170
- if (next.plugins) {
171
- const entries = Object.entries(next.plugins).sort(([a], [b]) => a.localeCompare(b));
172
- let pluginBasePort = DEFAULT_PLUGIN_PORT_START;
173
-
174
- for (const [pluginId, plugin] of entries) {
175
- if (plugin.source === "local" && plugin.localPath) {
176
- const pluginPort = await pickAvailablePort(plugin.port ?? pluginBasePort, usedPorts);
177
- next.plugins[pluginId] = withLocalRuntimeUrl(plugin, pluginPort);
178
- pluginBasePort = pluginPort + 1;
179
- }
180
-
181
- if (plugin.ui?.source === "local" && plugin.ui.localPath) {
182
- const uiPort = await pickAvailablePort(plugin.ui.port ?? pluginBasePort, usedPorts);
183
- next.plugins[pluginId] = {
184
- ...next.plugins[pluginId]!,
185
- ui: withLocalRuntimeUrl(plugin.ui, uiPort),
186
- };
187
- pluginBasePort = uiPort + 1;
188
- }
189
- }
190
- }
191
-
192
- return next;
193
- }
@@ -1,49 +0,0 @@
1
- import { bosContract } from "../contract";
2
- import { type CliCommandMeta, cliCommandMeta } from "../contract.meta";
3
-
4
- export type CommandDescriptor = {
5
- key: keyof typeof bosContract;
6
- commandPath: string[];
7
- summary: string;
8
- meta: CliCommandMeta;
9
- procedure: (typeof bosContract)[keyof typeof bosContract];
10
- };
11
-
12
- function splitCamelCase(value: string): string[] {
13
- return value
14
- .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
15
- .split(/\s+/)
16
- .map((part) => part.trim())
17
- .filter(Boolean)
18
- .map((part) => part.toLowerCase());
19
- }
20
-
21
- export const commandCatalog: CommandDescriptor[] = (
22
- Object.entries(bosContract) as Array<
23
- [keyof typeof bosContract, (typeof bosContract)[keyof typeof bosContract]]
24
- >
25
- ).map(([key, procedure]) => {
26
- const meta = cliCommandMeta[key as keyof typeof cliCommandMeta] ?? {
27
- summary: splitCamelCase(String(key)).join(" "),
28
- };
29
- return {
30
- key,
31
- commandPath: meta.commandPath ?? splitCamelCase(String(key)),
32
- summary: meta.summary,
33
- meta,
34
- procedure,
35
- };
36
- });
37
-
38
- export function findCommandDescriptor(
39
- args: string[],
40
- ): { descriptor: CommandDescriptor; consumed: number } | null {
41
- const sorted = [...commandCatalog].sort((a, b) => b.commandPath.length - a.commandPath.length);
42
- for (const descriptor of sorted) {
43
- const parts = args.slice(0, descriptor.commandPath.length).map((part) => part.toLowerCase());
44
- if (parts.join(" ") === descriptor.commandPath.join(" ")) {
45
- return { descriptor, consumed: descriptor.commandPath.length };
46
- }
47
- }
48
- return null;
49
- }
@@ -1,61 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
- function stripVersionPrefix(version: string): string {
5
- return version.replace(/^[\^~>=]+/, "");
6
- }
7
-
8
- export function readRootCatalogVersion(
9
- projectDir: string,
10
- packageName: string,
11
- ): string | undefined {
12
- const pkgPath = join(projectDir, "package.json");
13
- if (!existsSync(pkgPath)) return undefined;
14
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")) as {
15
- workspaces?: { catalog?: Record<string, string> };
16
- };
17
- const version = pkg.workspaces?.catalog?.[packageName];
18
- return version ? stripVersionPrefix(version) : undefined;
19
- }
20
-
21
- export function readNodeModulesVersion(
22
- projectDir: string,
23
- packageName: string,
24
- ): string | undefined {
25
- const pkgPath = join(projectDir, "node_modules", packageName, "package.json");
26
- if (!existsSync(pkgPath)) return undefined;
27
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")) as { version?: string };
28
- return pkg.version;
29
- }
30
-
31
- export function readInstalledFrameworkVersion(
32
- projectDir: string,
33
- packageName: string,
34
- ): string | undefined {
35
- const pkgPath = join(projectDir, "package.json");
36
- if (!existsSync(pkgPath)) return undefined;
37
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")) as Record<string, unknown>;
38
- const deps = (pkg.dependencies ?? {}) as Record<string, string>;
39
- const devDeps = (pkg.devDependencies ?? {}) as Record<string, string>;
40
- const version = deps[packageName] || devDeps[packageName];
41
-
42
- if (!version) {
43
- return (
44
- readRootCatalogVersion(projectDir, packageName) ??
45
- readNodeModulesVersion(projectDir, packageName)
46
- );
47
- }
48
-
49
- if (version.startsWith("catalog:")) {
50
- return (
51
- readRootCatalogVersion(projectDir, packageName) ??
52
- readNodeModulesVersion(projectDir, packageName)
53
- );
54
- }
55
-
56
- if (version.startsWith("workspace:") || version.startsWith("file:")) {
57
- return readNodeModulesVersion(projectDir, packageName);
58
- }
59
-
60
- return stripVersionPrefix(version);
61
- }
package/src/cli/help.ts DELETED
@@ -1,13 +0,0 @@
1
- import { commandCatalog } from "./catalog";
2
-
3
- export function printHelp() {
4
- process.stdout.write(`everything-dev commands\n\n`);
5
-
6
- for (const command of commandCatalog) {
7
- process.stdout.write(` everything-dev ${command.commandPath.join(" ")}`);
8
- process.stdout.write(command.meta.longRunning ? " (long running)" : "");
9
- process.stdout.write(`\n ${command.summary}\n`);
10
- }
11
-
12
- process.stdout.write(`\n'bos' is an alias for 'everything-dev'.\n`);
13
- }
package/src/cli/infra.ts DELETED
@@ -1,190 +0,0 @@
1
- import { randomBytes } from "node:crypto";
2
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import * as p from "@clack/prompts";
5
- import type { RuntimeConfig } from "../types";
6
-
7
- const POSTGRES_USER = "everythingdev";
8
- const POSTGRES_PASSWORD = "everythingdev";
9
- const API_DATABASE_SECRET = "API_DATABASE_URL";
10
- const AUTH_DATABASE_SECRET = "AUTH_DATABASE_URL";
11
- const BASE_DATABASE_PORT = 5434;
12
-
13
- interface DatabaseSecretConfig {
14
- secret: string;
15
- slug: string;
16
- port: number;
17
- serviceName: string;
18
- databaseName: string;
19
- volumeName: string;
20
- url: string;
21
- }
22
-
23
- function uniqueSecrets(values: Array<string | undefined>): string[] {
24
- const secrets: string[] = [];
25
- const seen = new Set<string>();
26
-
27
- for (const value of values) {
28
- if (!value || seen.has(value)) continue;
29
- seen.add(value);
30
- secrets.push(value);
31
- }
32
-
33
- return secrets;
34
- }
35
-
36
- function getRuntimeSecrets(runtimeConfig: RuntimeConfig): string[] {
37
- const pluginSecrets = Object.values(runtimeConfig.plugins ?? {}).flatMap(
38
- (plugin) => plugin.secrets ?? [],
39
- );
40
-
41
- return uniqueSecrets([
42
- API_DATABASE_SECRET,
43
- AUTH_DATABASE_SECRET,
44
- ...(runtimeConfig.api.secrets ?? []),
45
- ...(runtimeConfig.auth?.secrets ?? []),
46
- ...pluginSecrets,
47
- ]);
48
- }
49
-
50
- function normalizeDatabaseSlug(secret: string): string {
51
- return secret.replace(/_DATABASE_URL$/, "").toLowerCase();
52
- }
53
-
54
- function buildDatabaseConfigs(secrets: string[]): DatabaseSecretConfig[] {
55
- const databaseSecrets = uniqueSecrets(
56
- secrets.filter((secret) => secret.endsWith("_DATABASE_URL")),
57
- );
58
-
59
- const additionalSecrets = databaseSecrets
60
- .filter((secret) => secret !== API_DATABASE_SECRET && secret !== AUTH_DATABASE_SECRET)
61
- .sort((a, b) => a.localeCompare(b));
62
-
63
- const orderedSecrets = [API_DATABASE_SECRET, AUTH_DATABASE_SECRET, ...additionalSecrets];
64
-
65
- return orderedSecrets.map((secret, index) => {
66
- const slug = normalizeDatabaseSlug(secret);
67
- const port =
68
- secret === API_DATABASE_SECRET
69
- ? 5432
70
- : secret === AUTH_DATABASE_SECRET
71
- ? 5433
72
- : BASE_DATABASE_PORT + index - 2;
73
-
74
- return {
75
- secret,
76
- slug,
77
- port,
78
- serviceName: `postgres-${slug.replace(/_/g, "-")}`,
79
- databaseName: `${slug}_db`,
80
- volumeName: `postgres_${slug}_data`,
81
- url: `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${slug}_db`,
82
- };
83
- });
84
- }
85
-
86
- function defaultSecretValue(
87
- secret: string,
88
- databases: Map<string, DatabaseSecretConfig>,
89
- options: { forExample: boolean },
90
- ): string {
91
- if (secret === "BETTER_AUTH_SECRET") {
92
- return options.forExample ? "" : randomBytes(32).toString("base64url");
93
- }
94
-
95
- if (secret === "CORS_ORIGIN") {
96
- return "http://localhost:3000";
97
- }
98
-
99
- return databases.get(secret)?.url ?? "";
100
- }
101
-
102
- function renderEnvFile(
103
- secrets: string[],
104
- databases: DatabaseSecretConfig[],
105
- options: { forExample: boolean },
106
- ): string {
107
- const databaseMap = new Map(databases.map((entry) => [entry.secret, entry]));
108
- const lines = [
109
- "# Generated from configured bos secrets",
110
- "# Update values as needed for your local environment",
111
- "",
112
- ];
113
-
114
- for (const secret of secrets) {
115
- lines.push(`${secret}=${defaultSecretValue(secret, databaseMap, options)}`);
116
- }
117
-
118
- return `${lines.join("\n")}\n`;
119
- }
120
-
121
- function renderDockerCompose(databases: DatabaseSecretConfig[]): string {
122
- const lines = [
123
- "x-pg-common: &pg-common",
124
- " image: postgres:17-alpine",
125
- " environment: &pg-env",
126
- ` POSTGRES_USER: ${POSTGRES_USER}`,
127
- ` POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}`,
128
- " healthcheck:",
129
- ' test: ["CMD-SHELL", "pg_isready -U everythingdev"]',
130
- " interval: 3s",
131
- " timeout: 3s",
132
- " retries: 5",
133
- "",
134
- "services:",
135
- ];
136
-
137
- for (const database of databases) {
138
- lines.push(` ${database.serviceName}:`);
139
- lines.push(" <<: *pg-common");
140
- lines.push(" environment:");
141
- lines.push(" <<: *pg-env");
142
- lines.push(` POSTGRES_DB: ${database.databaseName}`);
143
- lines.push(" ports:");
144
- lines.push(` - "${database.port}:5432"`);
145
- lines.push(" volumes:");
146
- lines.push(` - ${database.volumeName}:/var/lib/postgresql/data`);
147
- lines.push("");
148
- }
149
-
150
- lines.push("volumes:");
151
- for (const database of databases) {
152
- lines.push(` ${database.volumeName}:`);
153
- }
154
-
155
- return `${lines.join("\n")}\n`;
156
- }
157
-
158
- export function writeGeneratedInfra(configDir: string, runtimeConfig: RuntimeConfig): string[] {
159
- const secrets = getRuntimeSecrets(runtimeConfig);
160
- const databases = buildDatabaseConfigs(secrets);
161
- const envExamplePath = join(configDir, ".env.example");
162
- const dockerComposePath = join(configDir, "docker-compose.yml");
163
-
164
- writeFileSync(envExamplePath, renderEnvFile(secrets, databases, { forExample: true }));
165
- writeFileSync(dockerComposePath, renderDockerCompose(databases));
166
-
167
- return secrets;
168
- }
169
-
170
- export function ensureEnvFile(configDir: string): void {
171
- const envPath = join(configDir, ".env");
172
- const examplePath = join(configDir, ".env.example");
173
-
174
- if (existsSync(envPath) || !existsSync(examplePath)) return;
175
-
176
- const content = readFileSync(examplePath, "utf-8");
177
- const lines = content.split("\n");
178
- const secret = randomBytes(32).toString("base64url");
179
- const updated = lines
180
- .map((line) => {
181
- if (/^BETTER_AUTH_SECRET=/.test(line)) {
182
- return `BETTER_AUTH_SECRET=${secret}`;
183
- }
184
- return line;
185
- })
186
- .join("\n");
187
-
188
- writeFileSync(envPath, updated);
189
- p.log.info("Created .env from generated .env.example with generated BETTER_AUTH_SECRET");
190
- }