everything-dev 1.26.1 → 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 (166) hide show
  1. package/dist/api-contract.cjs.map +1 -1
  2. package/dist/api-contract.mjs.map +1 -1
  3. package/dist/cli/catalog.cjs.map +1 -1
  4. package/dist/cli/catalog.mjs.map +1 -1
  5. package/dist/cli/framework-version.cjs.map +1 -1
  6. package/dist/cli/framework-version.mjs.map +1 -1
  7. package/dist/cli/infra.cjs +1 -1
  8. package/dist/cli/infra.cjs.map +1 -1
  9. package/dist/cli/infra.mjs +1 -1
  10. package/dist/cli/infra.mjs.map +1 -1
  11. package/dist/cli/init.cjs +127 -121
  12. package/dist/cli/init.cjs.map +1 -1
  13. package/dist/cli/init.d.cts +6 -6
  14. package/dist/cli/init.d.cts.map +1 -1
  15. package/dist/cli/init.d.mts +6 -6
  16. package/dist/cli/init.d.mts.map +1 -1
  17. package/dist/cli/init.mjs +125 -121
  18. package/dist/cli/init.mjs.map +1 -1
  19. package/dist/cli/parse.cjs.map +1 -1
  20. package/dist/cli/parse.mjs.map +1 -1
  21. package/dist/cli/prompts.cjs +29 -25
  22. package/dist/cli/prompts.cjs.map +1 -1
  23. package/dist/cli/prompts.mjs +28 -25
  24. package/dist/cli/prompts.mjs.map +1 -1
  25. package/dist/cli/status.cjs.map +1 -1
  26. package/dist/cli/status.mjs.map +1 -1
  27. package/dist/cli/sync.cjs +46 -93
  28. package/dist/cli/sync.cjs.map +1 -1
  29. package/dist/cli/sync.mjs +49 -96
  30. package/dist/cli/sync.mjs.map +1 -1
  31. package/dist/cli/timing.cjs.map +1 -1
  32. package/dist/cli/timing.mjs.map +1 -1
  33. package/dist/cli/upgrade.cjs +41 -20
  34. package/dist/cli/upgrade.cjs.map +1 -1
  35. package/dist/cli/upgrade.mjs +43 -22
  36. package/dist/cli/upgrade.mjs.map +1 -1
  37. package/dist/cli.cjs +187 -12
  38. package/dist/cli.cjs.map +1 -1
  39. package/dist/cli.mjs +187 -12
  40. package/dist/cli.mjs.map +1 -1
  41. package/dist/components/dev-view.cjs.map +1 -1
  42. package/dist/components/dev-view.mjs.map +1 -1
  43. package/dist/components/streaming-view.cjs.map +1 -1
  44. package/dist/components/streaming-view.mjs.map +1 -1
  45. package/dist/config.cjs.map +1 -1
  46. package/dist/config.mjs.map +1 -1
  47. package/dist/contract.cjs +174 -173
  48. package/dist/contract.cjs.map +1 -1
  49. package/dist/contract.d.cts +48 -44
  50. package/dist/contract.d.cts.map +1 -1
  51. package/dist/contract.d.mts +48 -44
  52. package/dist/contract.d.mts.map +1 -1
  53. package/dist/contract.mjs +3 -1
  54. package/dist/contract.mjs.map +1 -1
  55. package/dist/dev-logs.cjs.map +1 -1
  56. package/dist/dev-logs.mjs.map +1 -1
  57. package/dist/dev-session.cjs +0 -1
  58. package/dist/dev-session.mjs +1 -1
  59. package/dist/fastkv.cjs.map +1 -1
  60. package/dist/fastkv.mjs.map +1 -1
  61. package/dist/index.cjs +2 -4
  62. package/dist/index.d.cts +3 -3
  63. package/dist/index.d.mts +3 -3
  64. package/dist/index.mjs +1 -2
  65. package/dist/integrity.cjs.map +1 -1
  66. package/dist/integrity.mjs.map +1 -1
  67. package/dist/internal/manifest-normalizer.cjs.map +1 -1
  68. package/dist/internal/manifest-normalizer.mjs.map +1 -1
  69. package/dist/merge.cjs.map +1 -1
  70. package/dist/merge.mjs.map +1 -1
  71. package/dist/near-cli.cjs +1 -1
  72. package/dist/near-cli.cjs.map +1 -1
  73. package/dist/near-cli.mjs +1 -1
  74. package/dist/near-cli.mjs.map +1 -1
  75. package/dist/orchestrator.cjs +1 -1
  76. package/dist/orchestrator.cjs.map +1 -1
  77. package/dist/orchestrator.mjs +1 -1
  78. package/dist/orchestrator.mjs.map +1 -1
  79. package/dist/plugin.cjs +182 -171
  80. package/dist/plugin.cjs.map +1 -1
  81. package/dist/plugin.d.cts +72 -39
  82. package/dist/plugin.d.cts.map +1 -1
  83. package/dist/plugin.d.mts +71 -39
  84. package/dist/plugin.d.mts.map +1 -1
  85. package/dist/plugin.mjs +170 -160
  86. package/dist/plugin.mjs.map +1 -1
  87. package/dist/sdk.cjs +2 -2
  88. package/dist/sdk.d.cts +1 -1
  89. package/dist/sdk.d.mts +1 -1
  90. package/dist/sdk.mjs +1 -1
  91. package/dist/service-descriptor.d.cts +34 -0
  92. package/dist/service-descriptor.d.cts.map +1 -0
  93. package/dist/service-descriptor.d.mts +36 -0
  94. package/dist/service-descriptor.d.mts.map +1 -0
  95. package/dist/shared.cjs.map +1 -1
  96. package/dist/shared.mjs.map +1 -1
  97. package/dist/types.cjs +184 -184
  98. package/dist/types.cjs.map +1 -1
  99. package/dist/types.d.cts +5 -5
  100. package/dist/types.d.mts +5 -5
  101. package/dist/types.mjs +1 -1
  102. package/dist/types.mjs.map +1 -1
  103. package/dist/ui/types.d.cts +1 -0
  104. package/dist/ui/types.d.cts.map +1 -1
  105. package/dist/ui/types.d.mts +1 -0
  106. package/dist/ui/types.d.mts.map +1 -1
  107. package/dist/utils/banner.cjs.map +1 -1
  108. package/dist/utils/banner.mjs.map +1 -1
  109. package/dist/utils/run.cjs.map +1 -1
  110. package/dist/utils/run.mjs.map +1 -1
  111. package/package.json +3 -3
  112. package/skills/init-upgrade/SKILL.md +22 -16
  113. package/skills/publish-sync/SKILL.md +7 -18
  114. package/dist/utils/path-match.cjs +0 -18
  115. package/dist/utils/path-match.cjs.map +0 -1
  116. package/dist/utils/path-match.mjs +0 -17
  117. package/dist/utils/path-match.mjs.map +0 -1
  118. package/src/api-contract.ts +0 -623
  119. package/src/app.ts +0 -193
  120. package/src/cli/catalog.ts +0 -49
  121. package/src/cli/framework-version.ts +0 -61
  122. package/src/cli/help.ts +0 -13
  123. package/src/cli/infra.ts +0 -190
  124. package/src/cli/init.ts +0 -1202
  125. package/src/cli/parse.ts +0 -147
  126. package/src/cli/prompts.ts +0 -135
  127. package/src/cli/snapshot.ts +0 -46
  128. package/src/cli/status.ts +0 -99
  129. package/src/cli/sync.ts +0 -518
  130. package/src/cli/timing.ts +0 -63
  131. package/src/cli/upgrade.ts +0 -828
  132. package/src/cli.ts +0 -516
  133. package/src/components/dev-view.tsx +0 -352
  134. package/src/components/streaming-view.ts +0 -177
  135. package/src/config.ts +0 -893
  136. package/src/contract.meta.ts +0 -140
  137. package/src/contract.ts +0 -325
  138. package/src/dev-logs.ts +0 -92
  139. package/src/dev-session.ts +0 -283
  140. package/src/fastkv.ts +0 -181
  141. package/src/index.ts +0 -8
  142. package/src/integrity.ts +0 -138
  143. package/src/internal/manifest-normalizer.ts +0 -290
  144. package/src/merge.ts +0 -187
  145. package/src/mf.ts +0 -147
  146. package/src/near-cli.ts +0 -259
  147. package/src/network.ts +0 -3
  148. package/src/orchestrator.ts +0 -493
  149. package/src/plugin.ts +0 -1821
  150. package/src/sdk.ts +0 -14
  151. package/src/service-descriptor.ts +0 -281
  152. package/src/shared.ts +0 -249
  153. package/src/sidebar.ts +0 -140
  154. package/src/types.ts +0 -330
  155. package/src/ui/head.ts +0 -83
  156. package/src/ui/index.ts +0 -5
  157. package/src/ui/metadata.ts +0 -95
  158. package/src/ui/router.ts +0 -88
  159. package/src/ui/runtime.ts +0 -42
  160. package/src/ui/types.ts +0 -64
  161. package/src/utils/banner.ts +0 -21
  162. package/src/utils/linkify.ts +0 -11
  163. package/src/utils/path-match.ts +0 -16
  164. package/src/utils/run.ts +0 -31
  165. package/src/utils/save-config.ts +0 -20
  166. 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
- }