@tdk-landscape/tdk-cli-core 1.3.87 → 1.3.89

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 (34) hide show
  1. package/README.md +4 -4
  2. package/cli/dist/backend-frameworks/elysia.js +39 -0
  3. package/cli/dist/backend-frameworks/express.js +50 -0
  4. package/cli/dist/backend-frameworks/fastify.js +44 -0
  5. package/cli/dist/backend-frameworks/registry.js +45 -0
  6. package/cli/dist/backend-frameworks/types.js +2 -0
  7. package/cli/dist/backend-languages/go.js +98 -0
  8. package/cli/dist/backend-languages/registry.js +2 -0
  9. package/cli/dist/commands/resource.js +35 -8
  10. package/cli/dist/frontend-frameworks/lit.js +65 -0
  11. package/cli/dist/frontend-frameworks/preact.js +63 -0
  12. package/cli/dist/frontend-frameworks/qwik.js +62 -0
  13. package/cli/dist/frontend-frameworks/registry.js +16 -3
  14. package/cli/dist/frontend-frameworks/solid.js +63 -0
  15. package/cli/dist/frontend-frameworks/svelte.js +68 -0
  16. package/cli/dist/frontend-frameworks/vanilla.js +60 -0
  17. package/cli/dist/utils/service-manifest.js +1 -0
  18. package/cli/package.json +2 -2
  19. package/engine/schemas/service-schema.json +30 -7
  20. package/engine/topologies/platform/docker/compose/compose.star +9 -1
  21. package/engine/topologies/platform/docker/dockerfile/language_dockerfile.star +34 -3
  22. package/engine/topologies/platform/docker/index.star +2 -0
  23. package/engine/topologies/tilt/generators/typescript/frontend_tsconfig.star +10 -1
  24. package/engine/topologies/tilt/generators/validators.star +4 -3
  25. package/engine/topologies/tilt/generators/vite/frameworks/lit.star +90 -0
  26. package/engine/topologies/tilt/generators/vite/frameworks/preact.star +92 -0
  27. package/engine/topologies/tilt/generators/vite/frameworks/qwik.star +92 -0
  28. package/engine/topologies/tilt/generators/vite/frameworks/solid.star +92 -0
  29. package/engine/topologies/tilt/generators/vite/frameworks/svelte.star +92 -0
  30. package/engine/topologies/tilt/generators/vite/frameworks/vanilla.star +90 -0
  31. package/engine/topologies/tilt/generators/vite/frontend.star +30 -0
  32. package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +7 -0
  33. package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +2 -2
  34. package/package.json +2 -2
package/README.md CHANGED
@@ -18,11 +18,11 @@ tdk up shop
18
18
  curl http://api.shop.localhost/api/orders-api/health
19
19
  ```
20
20
 
21
- ![TDK scaffolding a backend and a frontend, then listing the stack](docs/demo.svg)
21
+ ![TDK scaffolding a backend and a frontend, then listing the stack](docs/assets/demo.svg)
22
22
 
23
23
  *Scaffolding a backend and frontend, then listing the stack.*
24
24
 
25
- ![Top 9 places to use TDK CLI: scaffold a service, start a stack, hot reload, port management, auto-discovery, boot order, proxy routing, include infra, and config verify](docs/tdk-cli-top-9-uses.jpg)
25
+ ![Top 9 places to use TDK CLI: scaffold a service, start a stack, hot reload, port management, auto-discovery, boot order, proxy routing, include infra, and config verify](docs/assets/tdk-cli-top-9-uses.jpg)
26
26
 
27
27
  If Helm, Compose, or your existing Tilt setup already gives you a working local environment, keep using it. TDK CLI is for engineers managing several services who want a clear local service contract and one command to start the stack.
28
28
 
@@ -66,9 +66,9 @@ curl -fsSL https://tdk-landscape.github.io/install.sh | sh
66
66
  - [Features and license limits](docs/FEATURES.md)
67
67
  - [Honest comparison and known limits](docs/compare-honest.md)
68
68
  - [Public claims registry](docs/claims.md)
69
- - [Show HN draft](docs/show-hn.md)
69
+ - [Show HN draft](docs/drafts/show-hn.md)
70
70
  - [Architecture and repository map](docs/project-overview.md)
71
- - [Scale fixture measurements and caveats](docs/scale-bench.md)
71
+ - [Scale fixture measurements and caveats](docs/benchmarks/scale-bench.md)
72
72
 
73
73
  ## Requirements and support
74
74
 
@@ -0,0 +1,39 @@
1
+ export function getElysiaIndexTemplate(name) {
2
+ return `import { Elysia } from 'elysia';
3
+
4
+ const port = Number(process.env.PORT || 3000);
5
+
6
+ const app = new Elysia()
7
+ // Health check endpoint (required by TILT_RESOURCE_DEFAULTS.star)
8
+ .get('/health', () => ({ status: 'ok', service: '${name}' }))
9
+ .get('/health/live', () => ({ status: 'alive', timestamp: Date.now() }))
10
+ .get('/health/ready', ({ set }) => {
11
+ const dependencies: Record<string, string> = {};
12
+ let allReady = true;
13
+
14
+ // Add dependency checks here (database, cache, etc.)
15
+ // Mark allReady = false if any dependency is unhealthy
16
+
17
+ set.status = allReady ? 200 : 503;
18
+ return { status: allReady ? 'ready' : 'not_ready', dependencies };
19
+ })
20
+ .get('/', () => ({
21
+ service: '${name}',
22
+ version: '1.0.0',
23
+ endpoints: ['/health', '/health/live', '/health/ready']
24
+ }))
25
+ // Bind beyond loopback: Traefik reaches the container over the Docker network.
26
+ .listen({ port, hostname: '0.0.0.0' });
27
+
28
+ console.log('\\nšŸš€ ${name} running on http://localhost:' + app.server?.port);
29
+ console.log('šŸ“Š Health check: http://localhost:' + app.server?.port + '/health\\n');
30
+ `;
31
+ }
32
+ export const elysiaBackendProvider = {
33
+ id: "elysia",
34
+ label: "Bun + Elysia",
35
+ dependencies: { elysia: "^1.3.0" },
36
+ devDependencies: {},
37
+ createIndex: getElysiaIndexTemplate,
38
+ };
39
+ //# sourceMappingURL=elysia.js.map
@@ -0,0 +1,50 @@
1
+ export function getExpressIndexTemplate(name) {
2
+ return `import express from 'express';
3
+
4
+ const app = express();
5
+
6
+ // Health check endpoint (required by TILT_RESOURCE_DEFAULTS.star)
7
+ app.get('/health', (_req, res) => {
8
+ res.json({ status: 'ok', service: '${name}' });
9
+ });
10
+
11
+ app.get('/health/live', (_req, res) => {
12
+ res.json({ status: 'alive', timestamp: Date.now() });
13
+ });
14
+
15
+ app.get('/health/ready', async (_req, res) => {
16
+ const dependencies: Record<string, string> = {};
17
+ let allReady = true;
18
+
19
+ // Add dependency checks here (database, cache, etc.)
20
+ // Mark allReady = false if any dependency is unhealthy
21
+
22
+ const status = allReady ? 'ready' : 'not_ready';
23
+ res.status(allReady ? 200 : 503).json({ status, dependencies });
24
+ });
25
+
26
+ app.get('/', (_req, res) => {
27
+ res.json({
28
+ service: '${name}',
29
+ version: '1.0.0',
30
+ endpoints: ['/health', '/health/live', '/health/ready']
31
+ });
32
+ });
33
+
34
+ const port = Number(process.env.PORT || 3000);
35
+
36
+ // Bind beyond loopback: Traefik reaches the container over the Docker network.
37
+ app.listen(port, '0.0.0.0', () => {
38
+ console.log('\\nšŸš€ ${name} running on http://localhost:' + port);
39
+ console.log('šŸ“Š Health check: http://localhost:' + port + '/health\\n');
40
+ });
41
+ `;
42
+ }
43
+ export const expressBackendProvider = {
44
+ id: "express",
45
+ label: "Bun + Express",
46
+ dependencies: { express: "^5.1.0" },
47
+ devDependencies: { "@types/express": "^5.0.0" },
48
+ createIndex: getExpressIndexTemplate,
49
+ };
50
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1,44 @@
1
+ export function getFastifyIndexTemplate(name) {
2
+ return `import Fastify from 'fastify';
3
+
4
+ const app = Fastify();
5
+
6
+ // Health check endpoint (required by TILT_RESOURCE_DEFAULTS.star)
7
+ app.get('/health', async () => ({ status: 'ok', service: '${name}' }));
8
+
9
+ app.get('/health/live', async () => ({ status: 'alive', timestamp: Date.now() }));
10
+
11
+ app.get('/health/ready', async (_request, reply) => {
12
+ const dependencies: Record<string, string> = {};
13
+ let allReady = true;
14
+
15
+ // Add dependency checks here (database, cache, etc.)
16
+ // Mark allReady = false if any dependency is unhealthy
17
+
18
+ const status = allReady ? 'ready' : 'not_ready';
19
+ return reply.code(allReady ? 200 : 503).send({ status, dependencies });
20
+ });
21
+
22
+ app.get('/', async () => ({
23
+ service: '${name}',
24
+ version: '1.0.0',
25
+ endpoints: ['/health', '/health/live', '/health/ready']
26
+ }));
27
+
28
+ const port = Number(process.env.PORT || 3000);
29
+
30
+ // Bind beyond loopback: Traefik reaches the container over the Docker network.
31
+ await app.listen({ port, host: '0.0.0.0' });
32
+
33
+ console.log('\\nšŸš€ ${name} running on http://localhost:' + port);
34
+ console.log('šŸ“Š Health check: http://localhost:' + port + '/health\\n');
35
+ `;
36
+ }
37
+ export const fastifyBackendProvider = {
38
+ id: "fastify",
39
+ label: "Bun + Fastify",
40
+ dependencies: { fastify: "^5.0.0" },
41
+ devDependencies: {},
42
+ createIndex: getFastifyIndexTemplate,
43
+ };
44
+ //# sourceMappingURL=fastify.js.map
@@ -0,0 +1,45 @@
1
+ import { getBackendIndexTemplate } from "../backend-languages/bun.js";
2
+ import { TdkError } from "../utils/errors.js";
3
+ import { elysiaBackendProvider } from "./elysia.js";
4
+ import { expressBackendProvider } from "./express.js";
5
+ import { fastifyBackendProvider } from "./fastify.js";
6
+ /** Hono is the historical default; omitting --framework keeps the exact historical output. */
7
+ export const DEFAULT_BACKEND_FRAMEWORK = "hono";
8
+ export const honoBackendProvider = {
9
+ id: "hono",
10
+ label: "Bun + Hono",
11
+ dependencies: { hono: "^4.0.0" },
12
+ devDependencies: {},
13
+ createIndex: getBackendIndexTemplate,
14
+ };
15
+ export const BACKEND_FRAMEWORKS = {
16
+ hono: honoBackendProvider,
17
+ express: expressBackendProvider,
18
+ elysia: elysiaBackendProvider,
19
+ fastify: fastifyBackendProvider,
20
+ };
21
+ export function getBackendFramework(frameworkId) {
22
+ const id = (frameworkId ?? DEFAULT_BACKEND_FRAMEWORK).trim().toLowerCase();
23
+ const provider = Object.hasOwn(BACKEND_FRAMEWORKS, id) ? BACKEND_FRAMEWORKS[id] : undefined;
24
+ if (!provider) {
25
+ const supportedIds = Object.keys(BACKEND_FRAMEWORKS).join(", ");
26
+ throw new TdkError(`Unknown backend framework "${frameworkId}". Supported frameworks: ${supportedIds}.`, [`Use one of: ${supportedIds}`, `Omit --framework to use ${DEFAULT_BACKEND_FRAMEWORK}`]);
27
+ }
28
+ return provider;
29
+ }
30
+ /**
31
+ * Returns the provider for an explicit `--framework` on a backend, or undefined when none was given
32
+ * (the historical Hono scaffold). Python owns its runtime, so a framework cannot be combined with it.
33
+ */
34
+ export function resolveBackendFramework(resourceType, frameworkId, language) {
35
+ if (resourceType !== "backend" || frameworkId === undefined)
36
+ return undefined;
37
+ if (language?.createFiles) {
38
+ throw new TdkError(`--framework cannot be combined with --language ${language.id}.`, [
39
+ `The ${language.id} provider owns its runtime and framework`,
40
+ "Drop --framework, or use --language bun",
41
+ ]);
42
+ }
43
+ return getBackendFramework(frameworkId);
44
+ }
45
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Go has no reload process inside the image, so the dev command is only what a developer would run by
3
+ * hand. Tilt rebuilds the image when a watched file changes (the engine returns no live-update rules).
4
+ */
5
+ export const GO_DEV_COMMAND = "go run .";
6
+ export const goBackendProvider = {
7
+ id: "go",
8
+ label: "Go 1.23 (net/http)",
9
+ devCommand: GO_DEV_COMMAND,
10
+ watch: ["**/*.go", "go.mod", "go.sum"],
11
+ installHint: "go mod tidy # optional: Docker builds the image for you",
12
+ createFiles(name) {
13
+ return [
14
+ {
15
+ filename: "go.mod",
16
+ content: `module ${name}
17
+
18
+ go 1.23
19
+ `,
20
+ description: "Generating go.mod",
21
+ emoji: "šŸ“¦",
22
+ },
23
+ {
24
+ filename: "main.go",
25
+ content: `package main
26
+
27
+ import (
28
+ "encoding/json"
29
+ "log"
30
+ "net/http"
31
+ "os"
32
+ )
33
+
34
+ func writeJSON(w http.ResponseWriter, status int, body any) {
35
+ w.Header().Set("Content-Type", "application/json")
36
+ w.WriteHeader(status)
37
+ _ = json.NewEncoder(w).Encode(body)
38
+ }
39
+
40
+ func newMux() *http.ServeMux {
41
+ mux := http.NewServeMux()
42
+
43
+ // Health check endpoint (required by TILT_RESOURCE_DEFAULTS.star)
44
+ mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
45
+ writeJSON(w, http.StatusOK, map[string]string{"status": "ok", "service": "${name}"})
46
+ })
47
+
48
+ mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
49
+ writeJSON(w, http.StatusOK, map[string]any{
50
+ "service": "${name}",
51
+ "version": "1.0.0",
52
+ "endpoints": []string{"/health"},
53
+ })
54
+ })
55
+
56
+ return mux
57
+ }
58
+
59
+ func main() {
60
+ port := os.Getenv("PORT")
61
+ if port == "" {
62
+ port = "3000"
63
+ }
64
+
65
+ // ":" + port listens on every interface, which Traefik needs inside the container network.
66
+ log.Printf("${name} listening on :%s", port)
67
+ log.Fatal(http.ListenAndServe(":"+port, newMux()))
68
+ }
69
+ `,
70
+ description: "Generating backend source",
71
+ emoji: "šŸ’»",
72
+ },
73
+ {
74
+ filename: "main_test.go",
75
+ content: `package main
76
+
77
+ import (
78
+ "net/http"
79
+ "net/http/httptest"
80
+ "testing"
81
+ )
82
+
83
+ func TestHealth(t *testing.T) {
84
+ rec := httptest.NewRecorder()
85
+ newMux().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/health", nil))
86
+
87
+ if rec.Code != http.StatusOK {
88
+ t.Fatalf("GET /health = %d, want %d", rec.Code, http.StatusOK)
89
+ }
90
+ }
91
+ `,
92
+ description: "Generating smoke test",
93
+ emoji: "🧪",
94
+ },
95
+ ];
96
+ },
97
+ };
98
+ //# sourceMappingURL=go.js.map
@@ -1,10 +1,12 @@
1
1
  import { TdkError } from "../utils/errors.js";
2
2
  import { bunBackendProvider } from "./bun.js";
3
+ import { goBackendProvider } from "./go.js";
3
4
  import { pythonBackendProvider } from "./python.js";
4
5
  export const DEFAULT_BACKEND_LANGUAGE = "bun";
5
6
  export const BACKEND_LANGUAGES = {
6
7
  bun: bunBackendProvider,
7
8
  python: pythonBackendProvider,
9
+ go: goBackendProvider,
8
10
  };
9
11
  export function getBackendLanguage(languageId) {
10
12
  const id = (languageId ?? DEFAULT_BACKEND_LANGUAGE).trim().toLowerCase();
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync } from "node:fs";
2
2
  import { isAbsolute, relative, resolve } from "node:path";
3
3
  import chalk from "chalk";
4
4
  import { Command } from "commander";
5
+ import { resolveBackendFramework } from "../backend-frameworks/registry.js";
5
6
  import { getBackendIndexTemplate } from "../backend-languages/bun.js";
6
7
  import { resolveBackendLanguage } from "../backend-languages/registry.js";
7
8
  import { resolveFrontendFramework } from "../frontend-frameworks/registry.js";
@@ -50,6 +51,7 @@ export const TYPE_SPECIFIC = {
50
51
  healthCheck: "/health",
51
52
  },
52
53
  };
54
+ const BYO_RESTART_POLICIES = ["no", "on-failure", "unless-stopped", "always"];
53
55
  export function resolveByoPort(value, assignedPort, resources) {
54
56
  if (!value)
55
57
  return assignedPort;
@@ -69,6 +71,8 @@ export function createServiceJson(name, type, stack, port, extraFeatures = [], f
69
71
  const framework = resolveFrontendFramework(type, frameworkId);
70
72
  // Only an explicit selection is persisted: a missing `language` has always meant Bun.
71
73
  const language = languageId === undefined ? undefined : resolveBackendLanguage(type, languageId);
74
+ // Likewise a missing backend `framework` has always meant Hono.
75
+ const backendFramework = resolveBackendFramework(type, frameworkId, language);
72
76
  const typeSpecific = TYPE_SPECIFIC[type];
73
77
  const base = JSON.parse(JSON.stringify(BASE_TEMPLATE));
74
78
  for (const [key, value] of Object.entries(typeSpecific)) {
@@ -105,12 +109,14 @@ export function createServiceJson(name, type, stack, port, extraFeatures = [], f
105
109
  stack,
106
110
  port,
107
111
  ...(framework ? { framework: framework.id } : {}),
112
+ ...(backendFramework ? { framework: backendFramework.id } : {}),
108
113
  ...(language ? { language: language.id } : {}),
109
114
  };
110
115
  }
111
116
  export function createPackageJson(name, type, frameworkId) {
112
117
  const isFrontend = type === "frontend";
113
118
  const framework = resolveFrontendFramework(type, frameworkId);
119
+ const backendFramework = resolveBackendFramework(type, frameworkId);
114
120
  return {
115
121
  name: `@project/${name}`,
116
122
  version: "0.0.1",
@@ -129,7 +135,7 @@ export function createPackageJson(name, type, frameworkId) {
129
135
  "lint:fix": "biome check . --write",
130
136
  },
131
137
  dependencies: {
132
- ...(isFrontend ? {} : { hono: "^4.0.0" }),
138
+ ...(isFrontend ? {} : (backendFramework?.dependencies ?? { hono: "^4.0.0" })),
133
139
  ...(framework?.dependencies ?? {}),
134
140
  },
135
141
  devDependencies: {
@@ -142,6 +148,7 @@ export function createPackageJson(name, type, frameworkId) {
142
148
  "@biomejs/biome": "^2.5.13",
143
149
  ...(isFrontend ? { vite: "^5.0.0" } : {}),
144
150
  ...(framework?.devDependencies ?? {}),
151
+ ...(backendFramework?.devDependencies ?? {}),
145
152
  },
146
153
  };
147
154
  }
@@ -288,8 +295,8 @@ export const resourceCommand = new Command("resource")
288
295
  .description("Create a new resource (service) from scratch, or register an existing one")
289
296
  .argument("[name]", "Resource name (kebab-case)")
290
297
  .option("-t, --type <type>", "Resource type: backend, frontend, worker, bring-your-own, sdk", "backend")
291
- .option("--framework <id>", "Frontend framework: react (default), vue")
292
- .option("--language <id>", "Backend language: bun (default), python")
298
+ .option("--framework <id>", "Framework: frontend react (default), vue, svelte, preact, lit, solid, qwik, vanilla; backend hono (default), express, elysia, fastify")
299
+ .option("--language <id>", "Backend language: bun (default), python, go")
293
300
  .option("-s, --stack <stack>", "Stack to assign resource to", "default")
294
301
  .option("-p, --path <path>", "Custom path for resource directory")
295
302
  .option("--resource-path <path>", "Alias for --path (for backward compatibility)")
@@ -299,6 +306,7 @@ export const resourceCommand = new Command("resource")
299
306
  .option("--dockerfile <path>", "Path to Dockerfile relative to resource dir (for bring-your-own)")
300
307
  .option("--health-path <path>", "HTTP health check path (for bring-your-own)", "/health")
301
308
  .option("--no-proxy", "Disable the Traefik route (bring-your-own only)")
309
+ .option("--restart <policy>", "Compose restart policy: no, on-failure, unless-stopped, always (bring-your-own only; use no for one-shot jobs)")
302
310
  .option("--image <name>", "Docker image name instead of building from Dockerfile (for bring-your-own)")
303
311
  .option("--port <port>", "Port number (default: next free in 4000-5999)")
304
312
  .action(async (name, options) => {
@@ -350,6 +358,7 @@ export const resourceCommand = new Command("resource")
350
358
  }
351
359
  const frontendFramework = resolveFrontendFramework(resourceType, options.framework);
352
360
  const backendLanguage = resolveBackendLanguage(resourceType, options.language);
361
+ const backendFramework = resolveBackendFramework(resourceType, options.framework, backendLanguage);
353
362
  let dddEnabled = false;
354
363
  if (options.ddd) {
355
364
  if (resourceType !== "backend" && resourceType !== "worker") {
@@ -446,6 +455,18 @@ export const resourceCommand = new Command("resource")
446
455
  const nextPort = resourceType === "sdk"
447
456
  ? 0
448
457
  : assignPort(resourceType, allResources);
458
+ if (options.restart !== undefined) {
459
+ if (resourceType !== "bring-your-own") {
460
+ throw new TdkError("--restart can only be used with --type bring-your-own.", [
461
+ "Add --type bring-your-own, or drop --restart",
462
+ ]);
463
+ }
464
+ if (!BYO_RESTART_POLICIES.includes(options.restart)) {
465
+ throw new TdkError(`Unknown --restart policy "${options.restart}".`, [
466
+ `Use one of: ${BYO_RESTART_POLICIES.join(", ")}`,
467
+ ]);
468
+ }
469
+ }
449
470
  const assignedPort = resourceType === "bring-your-own"
450
471
  ? resolveByoPort(options.port, nextPort, allResources)
451
472
  : nextPort;
@@ -515,6 +536,7 @@ export const resourceCommand = new Command("resource")
515
536
  healthCheckPath: options.healthPath || "/health",
516
537
  ...(options.image ? { image: options.image } : { dockerfile }),
517
538
  ...(options.proxy === false ? { exposeViaProxy: false } : {}),
539
+ ...(options.restart ? { restart: options.restart } : {}),
518
540
  };
519
541
  const { writeFileSync } = await import("node:fs");
520
542
  writeFileSync(resolve(fullPath, "service.json"), JSON.stringify(byoServiceJson, null, 2));
@@ -562,8 +584,13 @@ This file contains the resource configuration for TDK.
562
584
  // Create directory structure for new resources
563
585
  console.log(chalk.blue("\nšŸ“ Creating directory structure..."));
564
586
  mkdirSync(fullPath, { recursive: true });
565
- mkdirSync(resolve(fullPath, "src"), { recursive: true });
566
- mkdirSync(resolve(fullPath, "tests"), { recursive: true });
587
+ // A provider that owns its runtime files only gets the folders it writes into (Go keeps its files at the root).
588
+ const ownedTopLevel = new Set((backendLanguage?.createFiles?.(resourceName) ?? []).map((file) => file.filename.split("/")[0]));
589
+ for (const folder of ["src", "tests"]) {
590
+ if (!backendLanguage?.createFiles || ownedTopLevel.has(folder)) {
591
+ mkdirSync(resolve(fullPath, folder), { recursive: true });
592
+ }
593
+ }
567
594
  if (resourceType === "frontend") {
568
595
  mkdirSync(resolve(fullPath, "public"), { recursive: true });
569
596
  }
@@ -573,8 +600,8 @@ This file contains the resource configuration for TDK.
573
600
  }
574
601
  }
575
602
  // Prepare file generation tasks
576
- const serviceJson = createServiceJson(resourceName, resourceType, stackName, assignedPort, dddEnabled ? ["ddd"] : [], frontendFramework?.id, options.language === undefined ? undefined : backendLanguage?.id);
577
- const packageJson = createPackageJson(resourceName, resourceType, frontendFramework?.id);
603
+ const serviceJson = createServiceJson(resourceName, resourceType, stackName, assignedPort, dddEnabled ? ["ddd"] : [], frontendFramework?.id ?? backendFramework?.id, options.language === undefined ? undefined : backendLanguage?.id);
604
+ const packageJson = createPackageJson(resourceName, resourceType, frontendFramework?.id ?? backendFramework?.id);
578
605
  const tasks = [
579
606
  {
580
607
  type: "json",
@@ -610,7 +637,7 @@ This file contains the resource configuration for TDK.
610
637
  tasks.push({
611
638
  type: "text",
612
639
  filename: "src/index.ts",
613
- content: getBackendIndexTemplate(resourceName),
640
+ content: (backendFramework?.createIndex ?? getBackendIndexTemplate)(resourceName),
614
641
  description: "Generating backend source",
615
642
  emoji: "šŸ’»",
616
643
  });
@@ -0,0 +1,65 @@
1
+ export const litFrontendProvider = {
2
+ id: "lit",
3
+ label: "Lit + Vite",
4
+ dependencies: {
5
+ lit: "^3.2.0",
6
+ },
7
+ devDependencies: {},
8
+ compilerOptions: {},
9
+ createFiles(name) {
10
+ return [
11
+ {
12
+ filename: "index.html",
13
+ content: `<!DOCTYPE html>
14
+ <html lang="en">
15
+ <head>
16
+ <meta charset="UTF-8" />
17
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
18
+ <title>${name}</title>
19
+ </head>
20
+ <body>
21
+ <app-root></app-root>
22
+ <script type="module" src="/src/main.ts"></script>
23
+ </body>
24
+ </html>
25
+ `,
26
+ description: "Generating HTML template",
27
+ emoji: "šŸ’»",
28
+ },
29
+ {
30
+ filename: "src/main.ts",
31
+ content: `import './app-root';
32
+ `,
33
+ description: "Generating Lit entry",
34
+ emoji: "šŸ’»",
35
+ },
36
+ {
37
+ filename: "src/app-root.ts",
38
+ content: `import { LitElement, css, html } from 'lit';
39
+
40
+ export class AppRoot extends LitElement {
41
+ static styles = css\`
42
+ :host {
43
+ display: block;
44
+ padding: 2rem;
45
+ font-family: system-ui;
46
+ }
47
+ \`;
48
+
49
+ render() {
50
+ return html\`
51
+ <h1>${name}</h1>
52
+ <p>Frontend resource created with TDK</p>
53
+ \`;
54
+ }
55
+ }
56
+
57
+ customElements.define('app-root', AppRoot);
58
+ `,
59
+ description: "Generating Lit app",
60
+ emoji: "šŸ’»",
61
+ },
62
+ ];
63
+ },
64
+ };
65
+ //# sourceMappingURL=lit.js.map
@@ -0,0 +1,63 @@
1
+ export const preactFrontendProvider = {
2
+ id: "preact",
3
+ label: "Preact + Vite",
4
+ dependencies: {
5
+ preact: "^10.26.0",
6
+ },
7
+ devDependencies: {
8
+ "@preact/preset-vite": "^2.10.0",
9
+ },
10
+ compilerOptions: {
11
+ jsx: "react-jsx",
12
+ jsxImportSource: "preact",
13
+ },
14
+ createFiles(name) {
15
+ return [
16
+ {
17
+ filename: "index.html",
18
+ content: `<!DOCTYPE html>
19
+ <html lang="en">
20
+ <head>
21
+ <meta charset="UTF-8" />
22
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
23
+ <title>${name}</title>
24
+ </head>
25
+ <body>
26
+ <div id="app"></div>
27
+ <script type="module" src="/src/main.tsx"></script>
28
+ </body>
29
+ </html>
30
+ `,
31
+ description: "Generating HTML template",
32
+ emoji: "šŸ’»",
33
+ },
34
+ {
35
+ filename: "src/main.tsx",
36
+ content: `import { render } from 'preact';
37
+ import App from './App';
38
+
39
+ render(<App />, document.getElementById('app')!);
40
+ `,
41
+ description: "Generating Preact entry",
42
+ emoji: "šŸ’»",
43
+ },
44
+ {
45
+ filename: "src/App.tsx",
46
+ content: `function App() {
47
+ return (
48
+ <div style={{ padding: '2rem', fontFamily: 'system-ui' }}>
49
+ <h1>${name}</h1>
50
+ <p>Frontend resource created with TDK</p>
51
+ </div>
52
+ );
53
+ }
54
+
55
+ export default App;
56
+ `,
57
+ description: "Generating Preact app",
58
+ emoji: "šŸ’»",
59
+ },
60
+ ];
61
+ },
62
+ };
63
+ //# sourceMappingURL=preact.js.map
@@ -0,0 +1,62 @@
1
+ export const qwikFrontendProvider = {
2
+ id: "qwik",
3
+ label: "Qwik + Vite",
4
+ dependencies: {
5
+ "@builder.io/qwik": "^1.12.0",
6
+ },
7
+ devDependencies: {},
8
+ compilerOptions: {
9
+ jsx: "react-jsx",
10
+ jsxImportSource: "@builder.io/qwik",
11
+ },
12
+ createFiles(name) {
13
+ return [
14
+ {
15
+ filename: "index.html",
16
+ content: `<!DOCTYPE html>
17
+ <html lang="en">
18
+ <head>
19
+ <meta charset="UTF-8" />
20
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
21
+ <title>${name}</title>
22
+ </head>
23
+ <body>
24
+ <div id="app"></div>
25
+ <script type="module" src="/src/main.tsx"></script>
26
+ </body>
27
+ </html>
28
+ `,
29
+ description: "Generating HTML template",
30
+ emoji: "šŸ’»",
31
+ },
32
+ {
33
+ filename: "src/main.tsx",
34
+ content: `import '@builder.io/qwik/qwikloader.js';
35
+ import { render } from '@builder.io/qwik';
36
+ import { App } from './App';
37
+
38
+ render(document.getElementById('app') as HTMLElement, <App />);
39
+ `,
40
+ description: "Generating Qwik entry",
41
+ emoji: "šŸ’»",
42
+ },
43
+ {
44
+ filename: "src/App.tsx",
45
+ content: `import { component$ } from '@builder.io/qwik';
46
+
47
+ export const App = component$(() => {
48
+ return (
49
+ <div style={{ padding: '2rem', fontFamily: 'system-ui' }}>
50
+ <h1>${name}</h1>
51
+ <p>Frontend resource created with TDK</p>
52
+ </div>
53
+ );
54
+ });
55
+ `,
56
+ description: "Generating Qwik app",
57
+ emoji: "šŸ’»",
58
+ },
59
+ ];
60
+ },
61
+ };
62
+ //# sourceMappingURL=qwik.js.map