kavoru 0.7.1 → 0.8.8

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/features.ts +72 -29
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kavoru",
3
- "version": "0.7.1",
3
+ "version": "0.8.8",
4
4
  "description": "Scaffold a new Kavoru (Elysia + Bun) backend from the official template",
5
5
  "type": "module",
6
6
  "bin": {
package/src/features.ts CHANGED
@@ -108,7 +108,7 @@ const FEATURE_PATHS: Record<FeatureId, string[]> = {
108
108
  ],
109
109
  resend: ["src/infra/resend"],
110
110
  cron: ["src/schedules"],
111
- docker: ["Dockerfile", "docker-compose.yaml", "docker/otel.Dockerfile"],
111
+ docker: ["docker-compose.yaml", "docker"],
112
112
  };
113
113
 
114
114
  const FEATURE_DEPENDENCIES: Partial<
@@ -510,7 +510,7 @@ async function patchEnvExample(
510
510
  async function patchDockerfile(projectDir: string, selection: FeatureSelection) {
511
511
  if (!selection.docker) return;
512
512
 
513
- const relativePath = "Dockerfile";
513
+ const relativePath = "docker/app/Dockerfile";
514
514
  const current = await readText(projectDir, relativePath);
515
515
  if (!current) return;
516
516
 
@@ -530,19 +530,43 @@ async function patchDockerfile(projectDir: string, selection: FeatureSelection)
530
530
  await writeText(projectDir, relativePath, content);
531
531
  }
532
532
 
533
- function buildAppEnvironment(selection: FeatureSelection): string {
534
- const lines = [" NODE_ENV: production"];
533
+ const DOCKER_KAFKA_ENV = `# KRaft broker config (Confluent cp-kafka 7.6.1)
534
+ CLUSTER_ID=MkU3OEVBNTcwNTJENDM2Qk
535
+ KAFKA_NODE_ID=0
536
+ KAFKA_PROCESS_ROLES=broker,controller
537
+ KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094
538
+ KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://localhost:9094
539
+ KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
540
+ KAFKA_CONTROLLER_QUORUM_VOTERS=0@kafka:9093
541
+ KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER
542
+ KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT
543
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1
544
+ KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1
545
+ KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1
546
+ KAFKA_LOG_DIRS=/tmp/kraft-combined-logs
547
+ `;
548
+
549
+ const DOCKER_OTEL_ENV =
550
+ "# otel-dev runs with CLI flags in Dockerfile; add overrides here if needed.\n";
551
+
552
+ const DOCKER_SPOTLIGHT_ENV =
553
+ "# Official Spotlight image; add overrides here if needed.\n";
554
+
555
+ function buildDockerAppEnv(selection: FeatureSelection): string {
556
+ const lines = [
557
+ "# Docker-only overrides (loaded after root .env)",
558
+ "NODE_ENV=production",
559
+ ];
535
560
  if (selection.kafka) {
536
- lines.push(" KAFKA_BROKERS: kafka:9092");
561
+ lines.push("KAFKA_BROKERS=kafka:9092");
537
562
  }
538
563
  if (selection.otel) {
539
- lines.push(" OTEL_EXPORTER_OTLP_ENDPOINT: http://otel:4318/v1/traces");
540
- lines.push(" OTEL_SERVICE_NAME: ${OTEL_SERVICE_NAME:-kavoru}");
564
+ lines.push("OTEL_EXPORTER_OTLP_ENDPOINT=http://otel:4318/v1/traces");
541
565
  }
542
566
  if (selection.sentry) {
543
- lines.push(" SENTRY_SPOTLIGHT: http://spotlight:8969/stream");
567
+ lines.push("SENTRY_SPOTLIGHT=http://spotlight:8969/stream");
544
568
  }
545
- return ` environment:\n${lines.join("\n")}\n`;
569
+ return `${lines.join("\n")}\n`;
546
570
  }
547
571
 
548
572
  function generateDockerCompose(selection: FeatureSelection): string {
@@ -552,29 +576,17 @@ function generateDockerCompose(selection: FeatureSelection): string {
552
576
  condition: service_started
553
577
  `
554
578
  : "";
555
- const appEnvironment = buildAppEnvironment(selection);
556
579
 
557
580
  const kafkaService = selection.kafka
558
581
  ? `
559
582
  kafka:
560
- image: confluentinc/cp-kafka:7.6.1
583
+ build:
584
+ context: docker/kafka
561
585
  hostname: kafka
562
586
  ports:
563
587
  - "9094:9094"
564
- environment:
565
- CLUSTER_ID: MkU3OEVBNTcwNTJENDM2Qk
566
- KAFKA_NODE_ID: "0"
567
- KAFKA_PROCESS_ROLES: broker,controller
568
- KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094
569
- KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,EXTERNAL://localhost:9094
570
- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
571
- KAFKA_CONTROLLER_QUORUM_VOTERS: 0@kafka:9093
572
- KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
573
- KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
574
- KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
575
- KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
576
- KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
577
- KAFKA_LOG_DIRS: /tmp/kraft-combined-logs
588
+ env_file:
589
+ - docker/kafka/.env
578
590
  networks:
579
591
  - app_network
580
592
  restart: unless-stopped
@@ -585,10 +597,11 @@ function generateDockerCompose(selection: FeatureSelection): string {
585
597
  ? `
586
598
  otel:
587
599
  build:
588
- context: .
589
- dockerfile: docker/otel.Dockerfile
600
+ context: docker/otel
590
601
  ports:
591
602
  - "4318:4318"
603
+ env_file:
604
+ - docker/otel/.env
592
605
  networks:
593
606
  - app_network
594
607
  restart: unless-stopped
@@ -598,9 +611,12 @@ function generateDockerCompose(selection: FeatureSelection): string {
598
611
  const spotlightService = selection.sentry
599
612
  ? `
600
613
  spotlight:
601
- image: ghcr.io/getsentry/spotlight:latest
614
+ build:
615
+ context: docker/spotlight
602
616
  ports:
603
617
  - "8969:8969"
618
+ env_file:
619
+ - docker/spotlight/.env
604
620
  networks:
605
621
  - app_network
606
622
  restart: unless-stopped
@@ -611,6 +627,7 @@ function generateDockerCompose(selection: FeatureSelection): string {
611
627
  app:
612
628
  build:
613
629
  context: .
630
+ dockerfile: docker/app/Dockerfile
614
631
  target: build
615
632
  args:
616
633
  PORT: \${PORT:-3131}
@@ -628,7 +645,8 @@ function generateDockerCompose(selection: FeatureSelection): string {
628
645
  restart: unless-stopped
629
646
  env_file:
630
647
  - .env
631
- ${appDependsOn}${appEnvironment} healthcheck:
648
+ - docker/app/.env
649
+ ${appDependsOn} healthcheck:
632
650
  test: ["CMD", "curl", "-f", "http://localhost:\${PORT}/healthz"]
633
651
  interval: 600s
634
652
  timeout: 300s
@@ -646,6 +664,31 @@ async function patchDockerCompose(
646
664
  selection: FeatureSelection,
647
665
  ) {
648
666
  if (!selection.docker) return;
667
+
668
+ if (!selection.kafka) {
669
+ await removePaths(projectDir, ["docker/kafka"]);
670
+ }
671
+ if (!selection.otel) {
672
+ await removePaths(projectDir, ["docker/otel"]);
673
+ }
674
+ if (!selection.sentry) {
675
+ await removePaths(projectDir, ["docker/spotlight"]);
676
+ }
677
+
678
+ await writeText(
679
+ projectDir,
680
+ "docker/app/.env",
681
+ buildDockerAppEnv(selection),
682
+ );
683
+ if (selection.kafka) {
684
+ await writeText(projectDir, "docker/kafka/.env", DOCKER_KAFKA_ENV);
685
+ }
686
+ if (selection.otel) {
687
+ await writeText(projectDir, "docker/otel/.env", DOCKER_OTEL_ENV);
688
+ }
689
+ if (selection.sentry) {
690
+ await writeText(projectDir, "docker/spotlight/.env", DOCKER_SPOTLIGHT_ENV);
691
+ }
649
692
  await writeText(projectDir, "docker-compose.yaml", generateDockerCompose(selection));
650
693
  }
651
694