@brewnet/cli 0.0.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/LICENSE +184 -0
- package/dist/admin-server-DQVIEHV3.js +14 -0
- package/dist/admin-server-DQVIEHV3.js.map +1 -0
- package/dist/boilerplate-manager-P6QYUU7Q.js +29 -0
- package/dist/boilerplate-manager-P6QYUU7Q.js.map +1 -0
- package/dist/chunk-2VWMDHGI.js +1393 -0
- package/dist/chunk-2VWMDHGI.js.map +1 -0
- package/dist/chunk-4TJMJZMO.js +1173 -0
- package/dist/chunk-4TJMJZMO.js.map +1 -0
- package/dist/chunk-BAVGYMGA.js +114 -0
- package/dist/chunk-BAVGYMGA.js.map +1 -0
- package/dist/chunk-DH2VK3YI.js +293 -0
- package/dist/chunk-DH2VK3YI.js.map +1 -0
- package/dist/chunk-HCHY5UIQ.js +301 -0
- package/dist/chunk-HCHY5UIQ.js.map +1 -0
- package/dist/chunk-JFPHGZ6Z.js +254 -0
- package/dist/chunk-JFPHGZ6Z.js.map +1 -0
- package/dist/chunk-SIXBB6JU.js +2973 -0
- package/dist/chunk-SIXBB6JU.js.map +1 -0
- package/dist/chunk-SYV6PK3R.js +181 -0
- package/dist/chunk-SYV6PK3R.js.map +1 -0
- package/dist/chunk-ZKMWE5AH.js +444 -0
- package/dist/chunk-ZKMWE5AH.js.map +1 -0
- package/dist/cloudflare-client-TFT6VCXF.js +32 -0
- package/dist/cloudflare-client-TFT6VCXF.js.map +1 -0
- package/dist/compose-generator-O7GSIJ2S.js +19 -0
- package/dist/compose-generator-O7GSIJ2S.js.map +1 -0
- package/dist/frameworks-Z7VXDGP4.js +18 -0
- package/dist/frameworks-Z7VXDGP4.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +7897 -0
- package/dist/index.js.map +1 -0
- package/dist/services/admin-daemon.d.ts +2 -0
- package/dist/services/admin-daemon.js +33 -0
- package/dist/services/admin-daemon.js.map +1 -0
- package/dist/stacks-M4FBTVO5.js +16 -0
- package/dist/stacks-M4FBTVO5.js.map +1 -0
- package/dist/state-2SI3P4JG.js +27 -0
- package/dist/state-2SI3P4JG.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/config/stacks.ts
|
|
4
|
+
var VALID_DB_DRIVERS = ["sqlite3", "postgres", "mysql"];
|
|
5
|
+
var STACK_CATALOG = [
|
|
6
|
+
// ── Go ──────────────────────────────────────────────────────────────────
|
|
7
|
+
{
|
|
8
|
+
id: "go-gin",
|
|
9
|
+
language: "Go",
|
|
10
|
+
framework: "Gin",
|
|
11
|
+
version: "1.22",
|
|
12
|
+
orm: "GORM",
|
|
13
|
+
isUnified: false,
|
|
14
|
+
buildSlow: false
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "go-echo",
|
|
18
|
+
language: "Go",
|
|
19
|
+
framework: "Echo v4",
|
|
20
|
+
version: "1.24",
|
|
21
|
+
orm: "GORM",
|
|
22
|
+
isUnified: false,
|
|
23
|
+
buildSlow: false
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "go-fiber",
|
|
27
|
+
language: "Go",
|
|
28
|
+
framework: "Fiber v3",
|
|
29
|
+
version: "1.25",
|
|
30
|
+
orm: "GORM",
|
|
31
|
+
isUnified: false,
|
|
32
|
+
buildSlow: false
|
|
33
|
+
},
|
|
34
|
+
// ── Rust ────────────────────────────────────────────────────────────────
|
|
35
|
+
{
|
|
36
|
+
id: "rust-actix-web",
|
|
37
|
+
language: "Rust",
|
|
38
|
+
framework: "Actix-web 4",
|
|
39
|
+
version: "1.88",
|
|
40
|
+
orm: "SQLx",
|
|
41
|
+
isUnified: false,
|
|
42
|
+
buildSlow: true
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "rust-axum",
|
|
46
|
+
language: "Rust",
|
|
47
|
+
framework: "Axum 0.8",
|
|
48
|
+
version: "1.88",
|
|
49
|
+
orm: "SQLx",
|
|
50
|
+
isUnified: false,
|
|
51
|
+
buildSlow: true
|
|
52
|
+
},
|
|
53
|
+
// ── Java ────────────────────────────────────────────────────────────────
|
|
54
|
+
{
|
|
55
|
+
id: "java-springboot",
|
|
56
|
+
language: "Java",
|
|
57
|
+
framework: "Spring Boot 3.3",
|
|
58
|
+
version: "21",
|
|
59
|
+
orm: "JPA / JDBC",
|
|
60
|
+
isUnified: false,
|
|
61
|
+
buildSlow: false
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "java-spring",
|
|
65
|
+
language: "Java",
|
|
66
|
+
framework: "Spring Framework 6.2",
|
|
67
|
+
version: "21",
|
|
68
|
+
orm: "JDBC / HikariCP",
|
|
69
|
+
isUnified: false,
|
|
70
|
+
buildSlow: false
|
|
71
|
+
},
|
|
72
|
+
// ── Kotlin ──────────────────────────────────────────────────────────────
|
|
73
|
+
{
|
|
74
|
+
id: "kotlin-ktor",
|
|
75
|
+
language: "Kotlin",
|
|
76
|
+
framework: "Ktor 3.1",
|
|
77
|
+
version: "2.1",
|
|
78
|
+
orm: "Exposed ORM",
|
|
79
|
+
isUnified: false,
|
|
80
|
+
buildSlow: false
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "kotlin-springboot",
|
|
84
|
+
language: "Kotlin",
|
|
85
|
+
framework: "Spring Boot 3.4",
|
|
86
|
+
version: "2.1",
|
|
87
|
+
orm: "JDBC / HikariCP",
|
|
88
|
+
isUnified: false,
|
|
89
|
+
buildSlow: false
|
|
90
|
+
},
|
|
91
|
+
// ── Node.js ─────────────────────────────────────────────────────────────
|
|
92
|
+
{
|
|
93
|
+
id: "nodejs-express",
|
|
94
|
+
language: "Node.js",
|
|
95
|
+
framework: "Express 5",
|
|
96
|
+
version: "22",
|
|
97
|
+
orm: "Prisma 6",
|
|
98
|
+
isUnified: false,
|
|
99
|
+
buildSlow: false
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "nodejs-nestjs",
|
|
103
|
+
language: "Node.js",
|
|
104
|
+
framework: "NestJS 11",
|
|
105
|
+
version: "22",
|
|
106
|
+
orm: "Prisma 6",
|
|
107
|
+
isUnified: false,
|
|
108
|
+
buildSlow: false
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "nodejs-nextjs",
|
|
112
|
+
language: "Node.js",
|
|
113
|
+
framework: "Next.js 15 (API Routes)",
|
|
114
|
+
version: "22",
|
|
115
|
+
orm: "Prisma 6",
|
|
116
|
+
isUnified: true,
|
|
117
|
+
buildSlow: false
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "nodejs-nextjs-full",
|
|
121
|
+
language: "Node.js",
|
|
122
|
+
framework: "Next.js 15 (Full-Stack)",
|
|
123
|
+
version: "22",
|
|
124
|
+
orm: "Prisma 6",
|
|
125
|
+
isUnified: true,
|
|
126
|
+
buildSlow: false
|
|
127
|
+
},
|
|
128
|
+
// ── Python ──────────────────────────────────────────────────────────────
|
|
129
|
+
{
|
|
130
|
+
id: "python-fastapi",
|
|
131
|
+
language: "Python",
|
|
132
|
+
framework: "FastAPI",
|
|
133
|
+
version: "3.12",
|
|
134
|
+
orm: "SQLAlchemy 2.0",
|
|
135
|
+
isUnified: false,
|
|
136
|
+
buildSlow: false
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "python-django",
|
|
140
|
+
language: "Python",
|
|
141
|
+
framework: "Django 6",
|
|
142
|
+
version: "3.13",
|
|
143
|
+
orm: "Django ORM",
|
|
144
|
+
isUnified: false,
|
|
145
|
+
buildSlow: false
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: "python-flask",
|
|
149
|
+
language: "Python",
|
|
150
|
+
framework: "Flask 3.1",
|
|
151
|
+
version: "3.13",
|
|
152
|
+
orm: "Flask-SQLAlchemy",
|
|
153
|
+
isUnified: false,
|
|
154
|
+
buildSlow: false
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
var VALID_STACK_IDS = new Set(
|
|
158
|
+
STACK_CATALOG.map((s) => s.id)
|
|
159
|
+
);
|
|
160
|
+
function getStackById(id) {
|
|
161
|
+
return STACK_CATALOG.find((s) => s.id === id);
|
|
162
|
+
}
|
|
163
|
+
function getStacksByLanguage() {
|
|
164
|
+
const result = {};
|
|
165
|
+
for (const stack of STACK_CATALOG) {
|
|
166
|
+
if (!result[stack.language]) {
|
|
167
|
+
result[stack.language] = [];
|
|
168
|
+
}
|
|
169
|
+
result[stack.language].push(stack);
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export {
|
|
175
|
+
VALID_DB_DRIVERS,
|
|
176
|
+
STACK_CATALOG,
|
|
177
|
+
VALID_STACK_IDS,
|
|
178
|
+
getStackById,
|
|
179
|
+
getStacksByLanguage
|
|
180
|
+
};
|
|
181
|
+
//# sourceMappingURL=chunk-SYV6PK3R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config/stacks.ts"],"sourcesContent":["/**\n * brewnet create-app — Stack Catalog\n *\n * Authoritative list of all 16 boilerplate stacks available via\n * `brewnet create-app`. Each entry maps to an orphan branch\n * `stack/<id>` in the brewnet-boilerplate GitHub repository.\n *\n * Source of truth: docs/CONNECT_BOILERPLATE.md\n *\n * @module config/stacks\n */\n\nimport type { StackEntry, DbDriver } from '@brewnet/shared';\n\n// ---------------------------------------------------------------------------\n// Re-export types for convenience\n// ---------------------------------------------------------------------------\n\nexport type { StackEntry, DbDriver };\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Valid database driver values accepted by the --database flag. */\nexport const VALID_DB_DRIVERS = ['sqlite3', 'postgres', 'mysql'] as const;\n\n// ---------------------------------------------------------------------------\n// Stack Catalog — 16 entries\n// ---------------------------------------------------------------------------\n\nexport const STACK_CATALOG: StackEntry[] = [\n // ── Go ──────────────────────────────────────────────────────────────────\n {\n id: 'go-gin',\n language: 'Go',\n framework: 'Gin',\n version: '1.22',\n orm: 'GORM',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'go-echo',\n language: 'Go',\n framework: 'Echo v4',\n version: '1.24',\n orm: 'GORM',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'go-fiber',\n language: 'Go',\n framework: 'Fiber v3',\n version: '1.25',\n orm: 'GORM',\n isUnified: false,\n buildSlow: false,\n },\n // ── Rust ────────────────────────────────────────────────────────────────\n {\n id: 'rust-actix-web',\n language: 'Rust',\n framework: 'Actix-web 4',\n version: '1.88',\n orm: 'SQLx',\n isUnified: false,\n buildSlow: true,\n },\n {\n id: 'rust-axum',\n language: 'Rust',\n framework: 'Axum 0.8',\n version: '1.88',\n orm: 'SQLx',\n isUnified: false,\n buildSlow: true,\n },\n // ── Java ────────────────────────────────────────────────────────────────\n {\n id: 'java-springboot',\n language: 'Java',\n framework: 'Spring Boot 3.3',\n version: '21',\n orm: 'JPA / JDBC',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'java-spring',\n language: 'Java',\n framework: 'Spring Framework 6.2',\n version: '21',\n orm: 'JDBC / HikariCP',\n isUnified: false,\n buildSlow: false,\n },\n // ── Kotlin ──────────────────────────────────────────────────────────────\n {\n id: 'kotlin-ktor',\n language: 'Kotlin',\n framework: 'Ktor 3.1',\n version: '2.1',\n orm: 'Exposed ORM',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'kotlin-springboot',\n language: 'Kotlin',\n framework: 'Spring Boot 3.4',\n version: '2.1',\n orm: 'JDBC / HikariCP',\n isUnified: false,\n buildSlow: false,\n },\n // ── Node.js ─────────────────────────────────────────────────────────────\n {\n id: 'nodejs-express',\n language: 'Node.js',\n framework: 'Express 5',\n version: '22',\n orm: 'Prisma 6',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'nodejs-nestjs',\n language: 'Node.js',\n framework: 'NestJS 11',\n version: '22',\n orm: 'Prisma 6',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'nodejs-nextjs',\n language: 'Node.js',\n framework: 'Next.js 15 (API Routes)',\n version: '22',\n orm: 'Prisma 6',\n isUnified: true,\n buildSlow: false,\n },\n {\n id: 'nodejs-nextjs-full',\n language: 'Node.js',\n framework: 'Next.js 15 (Full-Stack)',\n version: '22',\n orm: 'Prisma 6',\n isUnified: true,\n buildSlow: false,\n },\n // ── Python ──────────────────────────────────────────────────────────────\n {\n id: 'python-fastapi',\n language: 'Python',\n framework: 'FastAPI',\n version: '3.12',\n orm: 'SQLAlchemy 2.0',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'python-django',\n language: 'Python',\n framework: 'Django 6',\n version: '3.13',\n orm: 'Django ORM',\n isUnified: false,\n buildSlow: false,\n },\n {\n id: 'python-flask',\n language: 'Python',\n framework: 'Flask 3.1',\n version: '3.13',\n orm: 'Flask-SQLAlchemy',\n isUnified: false,\n buildSlow: false,\n },\n];\n\n/** Set of all valid stack IDs (derived from catalog for fast lookup). */\nexport const VALID_STACK_IDS: ReadonlySet<string> = new Set(\n STACK_CATALOG.map((s) => s.id),\n);\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Look up a stack entry by its ID.\n * Returns `undefined` if the ID is not in the catalog.\n */\nexport function getStackById(id: string): StackEntry | undefined {\n return STACK_CATALOG.find((s) => s.id === id);\n}\n\n/**\n * Group stacks by language for the two-step interactive selection prompt.\n *\n * @example\n * { 'Go': [go-gin, go-echo, go-fiber], 'Rust': [...], ... }\n */\nexport function getStacksByLanguage(): Record<string, StackEntry[]> {\n const result: Record<string, StackEntry[]> = {};\n for (const stack of STACK_CATALOG) {\n if (!result[stack.language]) {\n result[stack.language] = [];\n }\n result[stack.language]!.push(stack);\n }\n return result;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ACCESS_LOG_MAX_BYTES,
|
|
4
|
+
CLI_LOG_RETENTION_DAYS,
|
|
5
|
+
SCHEMA_VERSION
|
|
6
|
+
} from "./chunk-HCHY5UIQ.js";
|
|
7
|
+
|
|
8
|
+
// src/wizard/state.ts
|
|
9
|
+
import {
|
|
10
|
+
existsSync as existsSync3,
|
|
11
|
+
readFileSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
mkdirSync as mkdirSync2,
|
|
14
|
+
readdirSync as readdirSync2
|
|
15
|
+
} from "fs";
|
|
16
|
+
import { homedir as homedir2 } from "os";
|
|
17
|
+
import { join as join3 } from "path";
|
|
18
|
+
import Conf from "conf";
|
|
19
|
+
|
|
20
|
+
// src/config/defaults.ts
|
|
21
|
+
function createDefaultWizardState() {
|
|
22
|
+
return {
|
|
23
|
+
schemaVersion: SCHEMA_VERSION,
|
|
24
|
+
projectName: "my-homeserver",
|
|
25
|
+
projectPath: "~/brewnet/my-homeserver",
|
|
26
|
+
setupType: "full",
|
|
27
|
+
admin: {
|
|
28
|
+
username: "admin",
|
|
29
|
+
password: "",
|
|
30
|
+
storage: "local"
|
|
31
|
+
},
|
|
32
|
+
servers: {
|
|
33
|
+
webServer: { enabled: true, service: "traefik" },
|
|
34
|
+
fileServer: { enabled: false, service: "" },
|
|
35
|
+
gitServer: { enabled: true, service: "gitea", port: 3e3, sshPort: 3022 },
|
|
36
|
+
dbServer: {
|
|
37
|
+
enabled: true,
|
|
38
|
+
primary: "postgresql",
|
|
39
|
+
primaryVersion: "18.3",
|
|
40
|
+
dbName: "brewnet_db",
|
|
41
|
+
dbUser: "brewnet",
|
|
42
|
+
dbPassword: "",
|
|
43
|
+
adminUI: true,
|
|
44
|
+
pgadminEmail: "",
|
|
45
|
+
cache: ""
|
|
46
|
+
},
|
|
47
|
+
media: { enabled: false, services: [] },
|
|
48
|
+
sshServer: { enabled: false, port: 2222, passwordAuth: false, sftp: false },
|
|
49
|
+
appServer: { enabled: false },
|
|
50
|
+
fileBrowser: { enabled: false, mode: "" }
|
|
51
|
+
},
|
|
52
|
+
portRemapping: {},
|
|
53
|
+
devStack: {
|
|
54
|
+
languages: [],
|
|
55
|
+
frameworks: {},
|
|
56
|
+
frontend: null
|
|
57
|
+
},
|
|
58
|
+
boilerplate: {
|
|
59
|
+
generate: true,
|
|
60
|
+
sampleData: true,
|
|
61
|
+
devMode: "hot-reload"
|
|
62
|
+
},
|
|
63
|
+
domain: {
|
|
64
|
+
provider: "local",
|
|
65
|
+
name: "brewnet.local",
|
|
66
|
+
ssl: "self-signed",
|
|
67
|
+
cloudflare: {
|
|
68
|
+
enabled: false,
|
|
69
|
+
tunnelMode: "none",
|
|
70
|
+
quickTunnelUrl: "",
|
|
71
|
+
accountId: "",
|
|
72
|
+
apiToken: "",
|
|
73
|
+
tunnelId: "",
|
|
74
|
+
tunnelToken: "",
|
|
75
|
+
tunnelName: "",
|
|
76
|
+
zoneId: "",
|
|
77
|
+
zoneName: ""
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
domainConnections: []
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function applyFullInstallDefaults(state) {
|
|
84
|
+
return {
|
|
85
|
+
...state,
|
|
86
|
+
setupType: "full",
|
|
87
|
+
servers: {
|
|
88
|
+
...state.servers,
|
|
89
|
+
webServer: { enabled: true, service: "traefik" },
|
|
90
|
+
gitServer: { enabled: true, service: "gitea", port: 3e3, sshPort: 3022 },
|
|
91
|
+
dbServer: {
|
|
92
|
+
...state.servers.dbServer,
|
|
93
|
+
enabled: true,
|
|
94
|
+
primary: "postgresql",
|
|
95
|
+
primaryVersion: "18.3",
|
|
96
|
+
dbName: "brewnet_db",
|
|
97
|
+
dbUser: "brewnet",
|
|
98
|
+
adminUI: true,
|
|
99
|
+
pgadminEmail: "",
|
|
100
|
+
cache: ""
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function applyPartialInstallDefaults(state) {
|
|
106
|
+
return {
|
|
107
|
+
...state,
|
|
108
|
+
setupType: "partial",
|
|
109
|
+
servers: {
|
|
110
|
+
...state.servers,
|
|
111
|
+
webServer: { enabled: true, service: "traefik" },
|
|
112
|
+
fileServer: { enabled: false, service: "" },
|
|
113
|
+
gitServer: { enabled: true, service: "gitea", port: 3e3, sshPort: 3022 },
|
|
114
|
+
dbServer: {
|
|
115
|
+
enabled: false,
|
|
116
|
+
primary: "",
|
|
117
|
+
primaryVersion: "",
|
|
118
|
+
dbName: "",
|
|
119
|
+
dbUser: "",
|
|
120
|
+
dbPassword: "",
|
|
121
|
+
adminUI: false,
|
|
122
|
+
pgadminEmail: "",
|
|
123
|
+
cache: ""
|
|
124
|
+
},
|
|
125
|
+
media: { enabled: false, services: [] },
|
|
126
|
+
sshServer: { enabled: false, port: 2222, passwordAuth: false, sftp: false },
|
|
127
|
+
appServer: { enabled: false },
|
|
128
|
+
fileBrowser: { enabled: false, mode: "" }
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function applyMinimalInstallDefaults(state) {
|
|
133
|
+
return {
|
|
134
|
+
...state,
|
|
135
|
+
setupType: "minimal",
|
|
136
|
+
servers: {
|
|
137
|
+
...state.servers,
|
|
138
|
+
webServer: { enabled: true, service: "traefik" },
|
|
139
|
+
fileServer: { enabled: false, service: "" },
|
|
140
|
+
gitServer: { enabled: true, service: "gitea", port: 3e3, sshPort: 3022 },
|
|
141
|
+
dbServer: {
|
|
142
|
+
enabled: false,
|
|
143
|
+
primary: "",
|
|
144
|
+
primaryVersion: "",
|
|
145
|
+
dbName: "",
|
|
146
|
+
dbUser: "",
|
|
147
|
+
dbPassword: "",
|
|
148
|
+
adminUI: false,
|
|
149
|
+
pgadminEmail: "",
|
|
150
|
+
cache: ""
|
|
151
|
+
},
|
|
152
|
+
media: { enabled: false, services: [] },
|
|
153
|
+
sshServer: { enabled: false, port: 2222, passwordAuth: false, sftp: false },
|
|
154
|
+
appServer: { enabled: false },
|
|
155
|
+
fileBrowser: { enabled: false, mode: "" }
|
|
156
|
+
},
|
|
157
|
+
domain: {
|
|
158
|
+
...state.domain,
|
|
159
|
+
provider: "local",
|
|
160
|
+
cloudflare: {
|
|
161
|
+
...state.domain.cloudflare,
|
|
162
|
+
enabled: true,
|
|
163
|
+
tunnelMode: "quick"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
boilerplate: {
|
|
167
|
+
...state.boilerplate,
|
|
168
|
+
generate: false
|
|
169
|
+
},
|
|
170
|
+
devStack: {
|
|
171
|
+
...state.devStack,
|
|
172
|
+
languages: []
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/utils/logger.ts
|
|
178
|
+
import { existsSync as existsSync2, mkdirSync, appendFileSync } from "fs";
|
|
179
|
+
import { homedir } from "os";
|
|
180
|
+
import { join as join2 } from "path";
|
|
181
|
+
|
|
182
|
+
// src/utils/log-rotation.ts
|
|
183
|
+
import {
|
|
184
|
+
existsSync,
|
|
185
|
+
readdirSync,
|
|
186
|
+
statSync,
|
|
187
|
+
unlinkSync,
|
|
188
|
+
copyFileSync,
|
|
189
|
+
renameSync,
|
|
190
|
+
truncateSync
|
|
191
|
+
} from "fs";
|
|
192
|
+
import { join } from "path";
|
|
193
|
+
function cleanOldCliLogs(logsDir, retentionDays) {
|
|
194
|
+
if (!existsSync(logsDir)) return 0;
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
const thresholdMs = retentionDays * 24 * 60 * 60 * 1e3;
|
|
197
|
+
let deleted = 0;
|
|
198
|
+
const files = readdirSync(logsDir).filter(
|
|
199
|
+
(f) => /^brewnet-\d{4}-\d{2}-\d{2}\.log$/.test(f)
|
|
200
|
+
);
|
|
201
|
+
for (const file of files) {
|
|
202
|
+
const dateStr = file.replace("brewnet-", "").replace(".log", "");
|
|
203
|
+
const fileDate = /* @__PURE__ */ new Date(dateStr + "T00:00:00Z");
|
|
204
|
+
if (isNaN(fileDate.getTime())) continue;
|
|
205
|
+
if (now - fileDate.getTime() > thresholdMs) {
|
|
206
|
+
try {
|
|
207
|
+
unlinkSync(join(logsDir, file));
|
|
208
|
+
deleted++;
|
|
209
|
+
} catch {
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return deleted;
|
|
214
|
+
}
|
|
215
|
+
function rotateLargeFile(filePath, maxBytes, maxFiles) {
|
|
216
|
+
if (!existsSync(filePath)) return false;
|
|
217
|
+
const stat = statSync(filePath);
|
|
218
|
+
if (stat.size < maxBytes) return false;
|
|
219
|
+
const oldest = `${filePath}.${maxFiles}`;
|
|
220
|
+
if (existsSync(oldest)) {
|
|
221
|
+
try {
|
|
222
|
+
unlinkSync(oldest);
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
for (let i = maxFiles - 1; i >= 1; i--) {
|
|
227
|
+
const src = `${filePath}.${i}`;
|
|
228
|
+
const dst = `${filePath}.${i + 1}`;
|
|
229
|
+
if (existsSync(src)) {
|
|
230
|
+
try {
|
|
231
|
+
renameSync(src, dst);
|
|
232
|
+
} catch {
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
copyFileSync(filePath, `${filePath}.1`);
|
|
238
|
+
truncateSync(filePath, 0);
|
|
239
|
+
} catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
function runRotation(logsDir, projectPath) {
|
|
245
|
+
try {
|
|
246
|
+
cleanOldCliLogs(logsDir, CLI_LOG_RETENTION_DAYS);
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
const tunnelLog = join(logsDir, "tunnel.log");
|
|
250
|
+
try {
|
|
251
|
+
rotateLargeFile(tunnelLog, ACCESS_LOG_MAX_BYTES, 5);
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
const accessLog = join(projectPath, "logs", "access.log");
|
|
255
|
+
try {
|
|
256
|
+
rotateLargeFile(accessLog, ACCESS_LOG_MAX_BYTES, 5);
|
|
257
|
+
} catch {
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/utils/logger.ts
|
|
262
|
+
function createLogger(logsDir) {
|
|
263
|
+
if (!existsSync2(logsDir)) {
|
|
264
|
+
mkdirSync(logsDir, { recursive: true });
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
cleanOldCliLogs(logsDir, CLI_LOG_RETENTION_DAYS);
|
|
268
|
+
} catch {
|
|
269
|
+
}
|
|
270
|
+
function write(level, command, message, metadata) {
|
|
271
|
+
const entry = {
|
|
272
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
273
|
+
level,
|
|
274
|
+
command,
|
|
275
|
+
message,
|
|
276
|
+
metadata: metadata ?? {}
|
|
277
|
+
};
|
|
278
|
+
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
279
|
+
const filePath = join2(logsDir, `brewnet-${dateStr}.log`);
|
|
280
|
+
try {
|
|
281
|
+
appendFileSync(filePath, JSON.stringify(entry) + "\n", "utf-8");
|
|
282
|
+
} catch {
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
info(command, message, metadata) {
|
|
287
|
+
write("info", command, message, metadata);
|
|
288
|
+
},
|
|
289
|
+
warn(command, message, metadata) {
|
|
290
|
+
write("warn", command, message, metadata);
|
|
291
|
+
},
|
|
292
|
+
error(command, message, metadata) {
|
|
293
|
+
write("error", command, message, metadata);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
var logger = createLogger(join2(homedir(), ".brewnet", "logs"));
|
|
298
|
+
|
|
299
|
+
// src/wizard/state.ts
|
|
300
|
+
var BREWNET_DIR = join3(homedir2(), ".brewnet");
|
|
301
|
+
var PROJECTS_DIR = join3(BREWNET_DIR, "projects");
|
|
302
|
+
function getProjectDir(projectName) {
|
|
303
|
+
return join3(PROJECTS_DIR, projectName);
|
|
304
|
+
}
|
|
305
|
+
function getStateFilePath(projectName) {
|
|
306
|
+
return join3(getProjectDir(projectName), "selections.json");
|
|
307
|
+
}
|
|
308
|
+
var _globalConfig = null;
|
|
309
|
+
function getGlobalConfig() {
|
|
310
|
+
if (!_globalConfig) {
|
|
311
|
+
mkdirSync2(BREWNET_DIR, { recursive: true });
|
|
312
|
+
_globalConfig = new Conf({
|
|
313
|
+
cwd: BREWNET_DIR,
|
|
314
|
+
configName: "config",
|
|
315
|
+
defaults: { lastProject: "" }
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return _globalConfig;
|
|
319
|
+
}
|
|
320
|
+
function createState() {
|
|
321
|
+
return createDefaultWizardState();
|
|
322
|
+
}
|
|
323
|
+
function hasResumeState(projectName) {
|
|
324
|
+
return existsSync3(getStateFilePath(projectName));
|
|
325
|
+
}
|
|
326
|
+
function loadState(projectName) {
|
|
327
|
+
const filePath = getStateFilePath(projectName);
|
|
328
|
+
if (!existsSync3(filePath)) return null;
|
|
329
|
+
try {
|
|
330
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
331
|
+
const parsed = JSON.parse(raw);
|
|
332
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
333
|
+
logger.warn("wizard", "Saved state is not an object", { projectName });
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
const obj = parsed;
|
|
337
|
+
if (typeof obj.schemaVersion === "number" && obj.schemaVersion === 6) {
|
|
338
|
+
logger.warn(
|
|
339
|
+
"wizard",
|
|
340
|
+
`Schema version 6 detected \u2014 migrating to v7 (frontend array \u2192 single value)`,
|
|
341
|
+
{ projectName }
|
|
342
|
+
);
|
|
343
|
+
const devStack = obj.devStack;
|
|
344
|
+
if (devStack && Array.isArray(devStack.frontend)) {
|
|
345
|
+
const arr = devStack.frontend;
|
|
346
|
+
if (arr.includes("reactjs") || arr.includes("react")) {
|
|
347
|
+
devStack.frontend = "react";
|
|
348
|
+
} else if (arr.includes("vuejs") || arr.includes("vue")) {
|
|
349
|
+
devStack.frontend = "vue";
|
|
350
|
+
} else {
|
|
351
|
+
devStack.frontend = null;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
obj.schemaVersion = SCHEMA_VERSION;
|
|
355
|
+
}
|
|
356
|
+
if (typeof obj.schemaVersion === "number" && obj.schemaVersion < SCHEMA_VERSION) {
|
|
357
|
+
logger.warn(
|
|
358
|
+
"wizard",
|
|
359
|
+
`Schema version ${obj.schemaVersion} is outdated (current: ${SCHEMA_VERSION}). Resetting state.`,
|
|
360
|
+
{ projectName }
|
|
361
|
+
);
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
if (obj.schemaVersion !== SCHEMA_VERSION) {
|
|
365
|
+
logger.warn("wizard", "Schema version mismatch", {
|
|
366
|
+
projectName,
|
|
367
|
+
found: obj.schemaVersion,
|
|
368
|
+
expected: SCHEMA_VERSION
|
|
369
|
+
});
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
if (!Array.isArray(obj.domainConnections)) {
|
|
373
|
+
obj.domainConnections = [];
|
|
374
|
+
}
|
|
375
|
+
return parsed;
|
|
376
|
+
} catch (err) {
|
|
377
|
+
logger.warn("wizard", "Failed to load saved state", {
|
|
378
|
+
projectName,
|
|
379
|
+
error: err instanceof Error ? err.message : String(err)
|
|
380
|
+
});
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function saveState(state) {
|
|
385
|
+
const dir = getProjectDir(state.projectName);
|
|
386
|
+
mkdirSync2(dir, { recursive: true });
|
|
387
|
+
const filePath = join3(dir, "selections.json");
|
|
388
|
+
writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
|
|
389
|
+
try {
|
|
390
|
+
getGlobalConfig().set("lastProject", state.projectName);
|
|
391
|
+
} catch {
|
|
392
|
+
}
|
|
393
|
+
logger.info("wizard", "State saved", { projectName: state.projectName });
|
|
394
|
+
}
|
|
395
|
+
function resetState(projectName) {
|
|
396
|
+
const state = createDefaultWizardState();
|
|
397
|
+
const updated = {
|
|
398
|
+
...state,
|
|
399
|
+
projectName,
|
|
400
|
+
projectPath: `~/brewnet/${projectName}`
|
|
401
|
+
};
|
|
402
|
+
saveState(updated);
|
|
403
|
+
return updated;
|
|
404
|
+
}
|
|
405
|
+
function getLastProject() {
|
|
406
|
+
try {
|
|
407
|
+
const last = getGlobalConfig().get("lastProject");
|
|
408
|
+
return last || void 0;
|
|
409
|
+
} catch {
|
|
410
|
+
return void 0;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function listProjects() {
|
|
414
|
+
if (!existsSync3(PROJECTS_DIR)) return [];
|
|
415
|
+
try {
|
|
416
|
+
return readdirSync2(PROJECTS_DIR, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter(
|
|
417
|
+
(entry) => existsSync3(join3(PROJECTS_DIR, entry.name, "selections.json"))
|
|
418
|
+
).map((entry) => entry.name);
|
|
419
|
+
} catch {
|
|
420
|
+
return [];
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function _resetGlobalConfig() {
|
|
424
|
+
_globalConfig = null;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export {
|
|
428
|
+
applyFullInstallDefaults,
|
|
429
|
+
applyPartialInstallDefaults,
|
|
430
|
+
applyMinimalInstallDefaults,
|
|
431
|
+
runRotation,
|
|
432
|
+
logger,
|
|
433
|
+
getProjectDir,
|
|
434
|
+
getStateFilePath,
|
|
435
|
+
createState,
|
|
436
|
+
hasResumeState,
|
|
437
|
+
loadState,
|
|
438
|
+
saveState,
|
|
439
|
+
resetState,
|
|
440
|
+
getLastProject,
|
|
441
|
+
listProjects,
|
|
442
|
+
_resetGlobalConfig
|
|
443
|
+
};
|
|
444
|
+
//# sourceMappingURL=chunk-ZKMWE5AH.js.map
|