blumenjs 0.1.2 → 0.1.4

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.
@@ -3,6 +3,9 @@
3
3
  import { spawn, execSync } from "child_process";
4
4
 
5
5
  // cli/utils.ts
6
+ import * as fs from "fs";
7
+ import * as path from "path";
8
+ import { fileURLToPath } from "url";
6
9
  var c = {
7
10
  reset: "\x1B[0m",
8
11
  bold: "\x1B[1m",
@@ -24,10 +27,30 @@ var log = {
24
27
  step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
25
28
  blank: () => console.log("")
26
29
  };
30
+ function getVersion() {
31
+ try {
32
+ const thisFile = fileURLToPath(import.meta.url);
33
+ let dir = path.dirname(thisFile);
34
+ for (let i = 0; i < 5; i++) {
35
+ const pkgFile = path.join(dir, "package.json");
36
+ if (fs.existsSync(pkgFile)) {
37
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, "utf-8"));
38
+ if (pkg.name === "blumenjs" || pkg.name === "go-react-ssr") {
39
+ return pkg.version;
40
+ }
41
+ }
42
+ dir = path.dirname(dir);
43
+ }
44
+ return "0.0.0";
45
+ } catch {
46
+ return "0.0.0";
47
+ }
48
+ }
27
49
  function banner() {
50
+ const version = getVersion();
28
51
  console.log("");
29
52
  console.log(
30
- ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
53
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v${version}${c.reset}`
31
54
  );
32
55
  console.log(
33
56
  ` ${c.dim}The React framework powered by Go${c.reset}`
@@ -147,17 +170,11 @@ async function dev() {
147
170
  log.success(`${c.bold}Ready!${c.reset} All services are running.`);
148
171
  log.blank();
149
172
  console.log(
150
- ` ${c.dim}\u279C${c.reset} ${c.bold}App${c.reset}: ${c.cyan}http://localhost:3000${c.reset}`
151
- );
152
- console.log(
153
- ` ${c.dim}\u279C${c.reset} ${c.bold}SSR${c.reset}: ${c.dim}http://localhost:4000${c.reset}`
154
- );
155
- console.log(
156
- ` ${c.dim}\u279C${c.reset} ${c.bold}HMR${c.reset}: ${c.dim}http://localhost:3100${c.reset}`
173
+ ` ${c.dim}\u279C${c.reset} ${c.bold}App${c.reset}: ${c.cyan}http://localhost:3000${c.reset}`
157
174
  );
158
175
  log.blank();
159
176
  console.log(
160
- ` ${c.dim}Press ${c.bold}Ctrl+C${c.reset}${c.dim} to stop all services.${c.reset}`
177
+ ` ${c.dim}Press ${c.bold}Ctrl+C${c.reset}${c.dim} to stop.${c.reset}`
161
178
  );
162
179
  log.blank();
163
180
  divider();
@@ -231,10 +248,10 @@ async function build() {
231
248
 
232
249
  // cli/commands/start.ts
233
250
  import { spawn as spawn2 } from "child_process";
234
- import * as fs from "fs";
251
+ import * as fs2 from "fs";
235
252
  async function start() {
236
253
  banner();
237
- if (!fs.existsSync("dist/ssr-server.js")) {
254
+ if (!fs2.existsSync("dist/ssr-server.js")) {
238
255
  log.error("Production build not found.");
239
256
  log.info(
240
257
  `Run ${c.bold}blumen build${c.reset} first to create a production build.`
@@ -319,23 +336,23 @@ async function start() {
319
336
  }
320
337
 
321
338
  // cli/commands/create.ts
322
- import * as fs2 from "fs";
323
- import * as path from "path";
339
+ import * as fs3 from "fs";
340
+ import * as path2 from "path";
324
341
  import { execSync as execSync3 } from "child_process";
325
342
  function getFrameworkRoot() {
326
- const cliEntry = fs2.realpathSync(process.argv[1]);
327
- const cliDir = path.dirname(cliEntry);
328
- return path.resolve(cliDir, "..");
343
+ const cliEntry = fs3.realpathSync(process.argv[1]);
344
+ const cliDir = path2.dirname(cliEntry);
345
+ return path2.resolve(cliDir, "..");
329
346
  }
330
347
  function readProjectFile(relativePath) {
331
348
  const root = getFrameworkRoot();
332
- const bundledPath = path.join(root, "templates", relativePath);
333
- if (fs2.existsSync(bundledPath)) {
334
- return fs2.readFileSync(bundledPath, "utf-8");
349
+ const bundledPath = path2.join(root, "templates", relativePath);
350
+ if (fs3.existsSync(bundledPath)) {
351
+ return fs3.readFileSync(bundledPath, "utf-8");
335
352
  }
336
- const sourcePath = path.join(root, relativePath);
337
- if (fs2.existsSync(sourcePath)) {
338
- return fs2.readFileSync(sourcePath, "utf-8");
353
+ const sourcePath = path2.join(root, relativePath);
354
+ if (fs3.existsSync(sourcePath)) {
355
+ return fs3.readFileSync(sourcePath, "utf-8");
339
356
  }
340
357
  throw new Error(`Template file not found: ${relativePath}`);
341
358
  }
@@ -538,10 +555,71 @@ export function Link({ href, children, onClick, target, ...rest }: LinkProps) {
538
555
 
539
556
  export default Link;
540
557
  `;
558
+ var DOCKERFILE = `# \u2500\u2500 Stage 1: Build Go server \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
559
+ FROM golang:1.22-alpine AS go-builder
560
+ WORKDIR /app
561
+ COPY go-server/ go-server/
562
+ WORKDIR /app/go-server
563
+ RUN go build -o /app/blumen-server main.go
564
+
565
+ # \u2500\u2500 Stage 2: Build Node SSR + client bundle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
566
+ FROM node:20-alpine AS node-builder
567
+ WORKDIR /app
568
+ COPY package.json tsconfig.json webpack.config.js ./
569
+ COPY app/ app/
570
+ COPY node-ssr/ node-ssr/
571
+ COPY scripts/ scripts/
572
+ RUN npm install --production=false
573
+ RUN npx tsx scripts/generate-routes.ts
574
+ RUN npx webpack --mode production
575
+ RUN npx esbuild node-ssr/server.ts --bundle --platform=node --format=esm \\
576
+ --outfile=dist/ssr-server.js --external:react --external:react-dom
577
+
578
+ # \u2500\u2500 Stage 3: Production image \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
579
+ FROM node:20-alpine
580
+ RUN apk add --no-cache libc6-compat
581
+ WORKDIR /app
582
+
583
+ # Copy Go binary
584
+ COPY --from=go-builder /app/blumen-server ./blumen-server
585
+
586
+ # Copy Node SSR server + production deps
587
+ COPY --from=node-builder /app/dist/ ./dist/
588
+ COPY --from=node-builder /app/static/ ./static/
589
+ COPY --from=node-builder /app/node_modules/ ./node_modules/
590
+ COPY --from=node-builder /app/package.json ./
591
+
592
+ EXPOSE 3000 4000
593
+
594
+ # Start both services (Go on :3000, Node SSR on :4000)
595
+ CMD sh -c './blumen-server & NODE_ENV=production node dist/ssr-server.js'
596
+ `;
597
+ var DOCKER_COMPOSE = `services:
598
+ app:
599
+ build: .
600
+ ports:
601
+ - "3000:3000"
602
+ environment:
603
+ - NODE_ENV=production
604
+ restart: unless-stopped
605
+ healthcheck:
606
+ test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000"]
607
+ interval: 30s
608
+ timeout: 5s
609
+ retries: 3
610
+ start_period: 10s
611
+ `;
612
+ var DOCKERIGNORE = `node_modules
613
+ dist
614
+ static/js/bundle.js
615
+ .git
616
+ *.log
617
+ .DS_Store
618
+ `;
541
619
  function writeFile(base, relPath, content) {
542
- const fullPath = path.join(base, relPath);
543
- fs2.mkdirSync(path.dirname(fullPath), { recursive: true });
544
- fs2.writeFileSync(fullPath, content, "utf-8");
620
+ const fullPath = path2.join(base, relPath);
621
+ fs3.mkdirSync(path2.dirname(fullPath), { recursive: true });
622
+ fs3.writeFileSync(fullPath, content, "utf-8");
545
623
  }
546
624
  function getTemplateFiles(projectName) {
547
625
  return [
@@ -563,7 +641,11 @@ function getTemplateFiles(projectName) {
563
641
  ["go-server/main.go", readProjectFile("go-server/main.go")],
564
642
  ["scripts/generate-routes.ts", readProjectFile("scripts/generate-routes.ts")],
565
643
  // Placeholder
566
- ["static/js/.gitkeep", ""]
644
+ ["static/js/.gitkeep", ""],
645
+ // Docker support (production deployment)
646
+ ["Dockerfile", DOCKERFILE],
647
+ ["docker-compose.yml", DOCKER_COMPOSE],
648
+ [".dockerignore", DOCKERIGNORE]
567
649
  ];
568
650
  }
569
651
  async function create(projectName) {
@@ -578,8 +660,8 @@ async function create(projectName) {
578
660
  );
579
661
  process.exit(1);
580
662
  }
581
- const projectDir = path.resolve(process.cwd(), projectName);
582
- if (fs2.existsSync(projectDir)) {
663
+ const projectDir = path2.resolve(process.cwd(), projectName);
664
+ if (fs3.existsSync(projectDir)) {
583
665
  log.error(`Directory ${c.bold}${projectName}${c.reset} already exists.`);
584
666
  process.exit(1);
585
667
  }
@@ -628,7 +710,6 @@ async function create(projectName) {
628
710
  }
629
711
 
630
712
  // cli/blumen.ts
631
- var VERSION = "0.1.0";
632
713
  async function main() {
633
714
  const command = process.argv[2];
634
715
  if (!command || command === "--help" || command === "-h") {
@@ -653,8 +734,8 @@ async function main() {
653
734
  console.log("");
654
735
  return;
655
736
  }
656
- if (command === "--version" || command === "-v") {
657
- console.log(`blumen v${VERSION}`);
737
+ if (command === "--version" || command === "-v" || command === "version") {
738
+ console.log(`blumen v${getVersion()}`);
658
739
  return;
659
740
  }
660
741
  switch (command) {
@@ -2,6 +2,9 @@
2
2
  import { execSync } from "child_process";
3
3
 
4
4
  // cli/utils.ts
5
+ import * as fs from "fs";
6
+ import * as path from "path";
7
+ import { fileURLToPath } from "url";
5
8
  var c = {
6
9
  reset: "\x1B[0m",
7
10
  bold: "\x1B[1m",
@@ -23,10 +26,30 @@ var log = {
23
26
  step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
24
27
  blank: () => console.log("")
25
28
  };
29
+ function getVersion() {
30
+ try {
31
+ const thisFile = fileURLToPath(import.meta.url);
32
+ let dir = path.dirname(thisFile);
33
+ for (let i = 0; i < 5; i++) {
34
+ const pkgFile = path.join(dir, "package.json");
35
+ if (fs.existsSync(pkgFile)) {
36
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, "utf-8"));
37
+ if (pkg.name === "blumenjs" || pkg.name === "go-react-ssr") {
38
+ return pkg.version;
39
+ }
40
+ }
41
+ dir = path.dirname(dir);
42
+ }
43
+ return "0.0.0";
44
+ } catch {
45
+ return "0.0.0";
46
+ }
47
+ }
26
48
  function banner() {
49
+ const version = getVersion();
27
50
  console.log("");
28
51
  console.log(
29
- ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
52
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v${version}${c.reset}`
30
53
  );
31
54
  console.log(
32
55
  ` ${c.dim}The React framework powered by Go${c.reset}`
@@ -1,9 +1,12 @@
1
1
  // cli/commands/create.ts
2
- import * as fs from "fs";
3
- import * as path from "path";
2
+ import * as fs2 from "fs";
3
+ import * as path2 from "path";
4
4
  import { execSync } from "child_process";
5
5
 
6
6
  // cli/utils.ts
7
+ import * as fs from "fs";
8
+ import * as path from "path";
9
+ import { fileURLToPath } from "url";
7
10
  var c = {
8
11
  reset: "\x1B[0m",
9
12
  bold: "\x1B[1m",
@@ -25,10 +28,30 @@ var log = {
25
28
  step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
26
29
  blank: () => console.log("")
27
30
  };
31
+ function getVersion() {
32
+ try {
33
+ const thisFile = fileURLToPath(import.meta.url);
34
+ let dir = path.dirname(thisFile);
35
+ for (let i = 0; i < 5; i++) {
36
+ const pkgFile = path.join(dir, "package.json");
37
+ if (fs.existsSync(pkgFile)) {
38
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, "utf-8"));
39
+ if (pkg.name === "blumenjs" || pkg.name === "go-react-ssr") {
40
+ return pkg.version;
41
+ }
42
+ }
43
+ dir = path.dirname(dir);
44
+ }
45
+ return "0.0.0";
46
+ } catch {
47
+ return "0.0.0";
48
+ }
49
+ }
28
50
  function banner() {
51
+ const version = getVersion();
29
52
  console.log("");
30
53
  console.log(
31
- ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
54
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v${version}${c.reset}`
32
55
  );
33
56
  console.log(
34
57
  ` ${c.dim}The React framework powered by Go${c.reset}`
@@ -65,19 +88,19 @@ async function select(question, options) {
65
88
 
66
89
  // cli/commands/create.ts
67
90
  function getFrameworkRoot() {
68
- const cliEntry = fs.realpathSync(process.argv[1]);
69
- const cliDir = path.dirname(cliEntry);
70
- return path.resolve(cliDir, "..");
91
+ const cliEntry = fs2.realpathSync(process.argv[1]);
92
+ const cliDir = path2.dirname(cliEntry);
93
+ return path2.resolve(cliDir, "..");
71
94
  }
72
95
  function readProjectFile(relativePath) {
73
96
  const root = getFrameworkRoot();
74
- const bundledPath = path.join(root, "templates", relativePath);
75
- if (fs.existsSync(bundledPath)) {
76
- return fs.readFileSync(bundledPath, "utf-8");
97
+ const bundledPath = path2.join(root, "templates", relativePath);
98
+ if (fs2.existsSync(bundledPath)) {
99
+ return fs2.readFileSync(bundledPath, "utf-8");
77
100
  }
78
- const sourcePath = path.join(root, relativePath);
79
- if (fs.existsSync(sourcePath)) {
80
- return fs.readFileSync(sourcePath, "utf-8");
101
+ const sourcePath = path2.join(root, relativePath);
102
+ if (fs2.existsSync(sourcePath)) {
103
+ return fs2.readFileSync(sourcePath, "utf-8");
81
104
  }
82
105
  throw new Error(`Template file not found: ${relativePath}`);
83
106
  }
@@ -280,10 +303,71 @@ export function Link({ href, children, onClick, target, ...rest }: LinkProps) {
280
303
 
281
304
  export default Link;
282
305
  `;
306
+ var DOCKERFILE = `# \u2500\u2500 Stage 1: Build Go server \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
307
+ FROM golang:1.22-alpine AS go-builder
308
+ WORKDIR /app
309
+ COPY go-server/ go-server/
310
+ WORKDIR /app/go-server
311
+ RUN go build -o /app/blumen-server main.go
312
+
313
+ # \u2500\u2500 Stage 2: Build Node SSR + client bundle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
314
+ FROM node:20-alpine AS node-builder
315
+ WORKDIR /app
316
+ COPY package.json tsconfig.json webpack.config.js ./
317
+ COPY app/ app/
318
+ COPY node-ssr/ node-ssr/
319
+ COPY scripts/ scripts/
320
+ RUN npm install --production=false
321
+ RUN npx tsx scripts/generate-routes.ts
322
+ RUN npx webpack --mode production
323
+ RUN npx esbuild node-ssr/server.ts --bundle --platform=node --format=esm \\
324
+ --outfile=dist/ssr-server.js --external:react --external:react-dom
325
+
326
+ # \u2500\u2500 Stage 3: Production image \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
327
+ FROM node:20-alpine
328
+ RUN apk add --no-cache libc6-compat
329
+ WORKDIR /app
330
+
331
+ # Copy Go binary
332
+ COPY --from=go-builder /app/blumen-server ./blumen-server
333
+
334
+ # Copy Node SSR server + production deps
335
+ COPY --from=node-builder /app/dist/ ./dist/
336
+ COPY --from=node-builder /app/static/ ./static/
337
+ COPY --from=node-builder /app/node_modules/ ./node_modules/
338
+ COPY --from=node-builder /app/package.json ./
339
+
340
+ EXPOSE 3000 4000
341
+
342
+ # Start both services (Go on :3000, Node SSR on :4000)
343
+ CMD sh -c './blumen-server & NODE_ENV=production node dist/ssr-server.js'
344
+ `;
345
+ var DOCKER_COMPOSE = `services:
346
+ app:
347
+ build: .
348
+ ports:
349
+ - "3000:3000"
350
+ environment:
351
+ - NODE_ENV=production
352
+ restart: unless-stopped
353
+ healthcheck:
354
+ test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000"]
355
+ interval: 30s
356
+ timeout: 5s
357
+ retries: 3
358
+ start_period: 10s
359
+ `;
360
+ var DOCKERIGNORE = `node_modules
361
+ dist
362
+ static/js/bundle.js
363
+ .git
364
+ *.log
365
+ .DS_Store
366
+ `;
283
367
  function writeFile(base, relPath, content) {
284
- const fullPath = path.join(base, relPath);
285
- fs.mkdirSync(path.dirname(fullPath), { recursive: true });
286
- fs.writeFileSync(fullPath, content, "utf-8");
368
+ const fullPath = path2.join(base, relPath);
369
+ fs2.mkdirSync(path2.dirname(fullPath), { recursive: true });
370
+ fs2.writeFileSync(fullPath, content, "utf-8");
287
371
  }
288
372
  function getTemplateFiles(projectName) {
289
373
  return [
@@ -305,7 +389,11 @@ function getTemplateFiles(projectName) {
305
389
  ["go-server/main.go", readProjectFile("go-server/main.go")],
306
390
  ["scripts/generate-routes.ts", readProjectFile("scripts/generate-routes.ts")],
307
391
  // Placeholder
308
- ["static/js/.gitkeep", ""]
392
+ ["static/js/.gitkeep", ""],
393
+ // Docker support (production deployment)
394
+ ["Dockerfile", DOCKERFILE],
395
+ ["docker-compose.yml", DOCKER_COMPOSE],
396
+ [".dockerignore", DOCKERIGNORE]
309
397
  ];
310
398
  }
311
399
  async function create(projectName) {
@@ -320,8 +408,8 @@ async function create(projectName) {
320
408
  );
321
409
  process.exit(1);
322
410
  }
323
- const projectDir = path.resolve(process.cwd(), projectName);
324
- if (fs.existsSync(projectDir)) {
411
+ const projectDir = path2.resolve(process.cwd(), projectName);
412
+ if (fs2.existsSync(projectDir)) {
325
413
  log.error(`Directory ${c.bold}${projectName}${c.reset} already exists.`);
326
414
  process.exit(1);
327
415
  }
@@ -2,6 +2,9 @@
2
2
  import { spawn, execSync } from "child_process";
3
3
 
4
4
  // cli/utils.ts
5
+ import * as fs from "fs";
6
+ import * as path from "path";
7
+ import { fileURLToPath } from "url";
5
8
  var c = {
6
9
  reset: "\x1B[0m",
7
10
  bold: "\x1B[1m",
@@ -23,10 +26,30 @@ var log = {
23
26
  step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
24
27
  blank: () => console.log("")
25
28
  };
29
+ function getVersion() {
30
+ try {
31
+ const thisFile = fileURLToPath(import.meta.url);
32
+ let dir = path.dirname(thisFile);
33
+ for (let i = 0; i < 5; i++) {
34
+ const pkgFile = path.join(dir, "package.json");
35
+ if (fs.existsSync(pkgFile)) {
36
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, "utf-8"));
37
+ if (pkg.name === "blumenjs" || pkg.name === "go-react-ssr") {
38
+ return pkg.version;
39
+ }
40
+ }
41
+ dir = path.dirname(dir);
42
+ }
43
+ return "0.0.0";
44
+ } catch {
45
+ return "0.0.0";
46
+ }
47
+ }
26
48
  function banner() {
49
+ const version = getVersion();
27
50
  console.log("");
28
51
  console.log(
29
- ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
52
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v${version}${c.reset}`
30
53
  );
31
54
  console.log(
32
55
  ` ${c.dim}The React framework powered by Go${c.reset}`
@@ -122,17 +145,11 @@ async function dev() {
122
145
  log.success(`${c.bold}Ready!${c.reset} All services are running.`);
123
146
  log.blank();
124
147
  console.log(
125
- ` ${c.dim}\u279C${c.reset} ${c.bold}App${c.reset}: ${c.cyan}http://localhost:3000${c.reset}`
126
- );
127
- console.log(
128
- ` ${c.dim}\u279C${c.reset} ${c.bold}SSR${c.reset}: ${c.dim}http://localhost:4000${c.reset}`
129
- );
130
- console.log(
131
- ` ${c.dim}\u279C${c.reset} ${c.bold}HMR${c.reset}: ${c.dim}http://localhost:3100${c.reset}`
148
+ ` ${c.dim}\u279C${c.reset} ${c.bold}App${c.reset}: ${c.cyan}http://localhost:3000${c.reset}`
132
149
  );
133
150
  log.blank();
134
151
  console.log(
135
- ` ${c.dim}Press ${c.bold}Ctrl+C${c.reset}${c.dim} to stop all services.${c.reset}`
152
+ ` ${c.dim}Press ${c.bold}Ctrl+C${c.reset}${c.dim} to stop.${c.reset}`
136
153
  );
137
154
  log.blank();
138
155
  divider();
@@ -1,8 +1,11 @@
1
1
  // cli/commands/start.ts
2
2
  import { spawn } from "child_process";
3
- import * as fs from "fs";
3
+ import * as fs2 from "fs";
4
4
 
5
5
  // cli/utils.ts
6
+ import * as fs from "fs";
7
+ import * as path from "path";
8
+ import { fileURLToPath } from "url";
6
9
  var c = {
7
10
  reset: "\x1B[0m",
8
11
  bold: "\x1B[1m",
@@ -24,10 +27,30 @@ var log = {
24
27
  step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
25
28
  blank: () => console.log("")
26
29
  };
30
+ function getVersion() {
31
+ try {
32
+ const thisFile = fileURLToPath(import.meta.url);
33
+ let dir = path.dirname(thisFile);
34
+ for (let i = 0; i < 5; i++) {
35
+ const pkgFile = path.join(dir, "package.json");
36
+ if (fs.existsSync(pkgFile)) {
37
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, "utf-8"));
38
+ if (pkg.name === "blumenjs" || pkg.name === "go-react-ssr") {
39
+ return pkg.version;
40
+ }
41
+ }
42
+ dir = path.dirname(dir);
43
+ }
44
+ return "0.0.0";
45
+ } catch {
46
+ return "0.0.0";
47
+ }
48
+ }
27
49
  function banner() {
50
+ const version = getVersion();
28
51
  console.log("");
29
52
  console.log(
30
- ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
53
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v${version}${c.reset}`
31
54
  );
32
55
  console.log(
33
56
  ` ${c.dim}The React framework powered by Go${c.reset}`
@@ -41,7 +64,7 @@ function divider() {
41
64
  // cli/commands/start.ts
42
65
  async function start() {
43
66
  banner();
44
- if (!fs.existsSync("dist/ssr-server.js")) {
67
+ if (!fs2.existsSync("dist/ssr-server.js")) {
45
68
  log.error("Production build not found.");
46
69
  log.info(
47
70
  `Run ${c.bold}blumen build${c.reset} first to create a production build.`
package/dist/cli/utils.js CHANGED
@@ -1,4 +1,7 @@
1
1
  // cli/utils.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import { fileURLToPath } from "url";
2
5
  var c = {
3
6
  reset: "\x1B[0m",
4
7
  bold: "\x1B[1m",
@@ -20,10 +23,30 @@ var log = {
20
23
  step: (msg) => console.log(` ${c.dim}\u2192${c.reset} ${msg}`),
21
24
  blank: () => console.log("")
22
25
  };
26
+ function getVersion() {
27
+ try {
28
+ const thisFile = fileURLToPath(import.meta.url);
29
+ let dir = path.dirname(thisFile);
30
+ for (let i = 0; i < 5; i++) {
31
+ const pkgFile = path.join(dir, "package.json");
32
+ if (fs.existsSync(pkgFile)) {
33
+ const pkg = JSON.parse(fs.readFileSync(pkgFile, "utf-8"));
34
+ if (pkg.name === "blumenjs" || pkg.name === "go-react-ssr") {
35
+ return pkg.version;
36
+ }
37
+ }
38
+ dir = path.dirname(dir);
39
+ }
40
+ return "0.0.0";
41
+ } catch {
42
+ return "0.0.0";
43
+ }
44
+ }
23
45
  function banner() {
46
+ const version = getVersion();
24
47
  console.log("");
25
48
  console.log(
26
- ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v0.1.0${c.reset}`
49
+ ` ${c.magenta}${c.bold}\u{1F338} Blumen${c.reset} ${c.dim}v${version}${c.reset}`
27
50
  );
28
51
  console.log(
29
52
  ` ${c.dim}The React framework powered by Go${c.reset}`
@@ -80,6 +103,7 @@ export {
80
103
  c,
81
104
  confirm,
82
105
  divider,
106
+ getVersion,
83
107
  log,
84
108
  select
85
109
  };
@@ -7,7 +7,7 @@ interface HomeProps {
7
7
 
8
8
  const HomePage: React.FC<HomeProps> = () => {
9
9
  return (
10
- <>
10
+ <div className="blumen-home">
11
11
  <style
12
12
  dangerouslySetInnerHTML={{
13
13
  __html: `
@@ -305,8 +305,7 @@ const HomePage: React.FC<HomeProps> = () => {
305
305
  `,
306
306
  }}
307
307
  />
308
- <div className="blumen-home">
309
- {/* Background effects */}
308
+ {/* Background effects */}
310
309
  <div className="blumen-bg" />
311
310
  <div className="blumen-orb blumen-orb-1" />
312
311
  <div className="blumen-orb blumen-orb-2" />
@@ -390,8 +389,7 @@ const HomePage: React.FC<HomeProps> = () => {
390
389
  </p>
391
390
  </div>
392
391
  </div>
393
- </div>
394
- </>
392
+ </div>
395
393
  );
396
394
  };
397
395
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blumenjs",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "The React framework powered by Go. Lightning-fast SSR with the DX you deserve.",
5
5
  "type": "module",
6
6
  "bin": {