@tdk-landscape/tdk-cli-core 1.3.37 → 1.3.39

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 (48) hide show
  1. package/dist/commands/config.js +1 -1
  2. package/dist/commands/config.js.map +1 -1
  3. package/dist/commands/doctor.d.ts.map +1 -1
  4. package/dist/commands/doctor.js +98 -6
  5. package/dist/commands/doctor.js.map +1 -1
  6. package/dist/commands/resource.js +1 -1
  7. package/dist/commands/resource.js.map +1 -1
  8. package/dist/generator/extension-fetch.d.ts +7 -0
  9. package/dist/generator/extension-fetch.d.ts.map +1 -1
  10. package/dist/generator/extension-fetch.js +40 -21
  11. package/dist/generator/extension-fetch.js.map +1 -1
  12. package/dist/generator/template-engine.d.ts.map +1 -1
  13. package/dist/generator/template-engine.js +42 -12
  14. package/dist/generator/template-engine.js.map +1 -1
  15. package/dist/types/index.d.ts +6 -0
  16. package/dist/types/index.d.ts.map +1 -1
  17. package/dist/types/index.js.map +1 -1
  18. package/dist/utils/docker.d.ts +3 -2
  19. package/dist/utils/docker.d.ts.map +1 -1
  20. package/dist/utils/docker.js +12 -6
  21. package/dist/utils/docker.js.map +1 -1
  22. package/dist/utils/errors.d.ts +1 -0
  23. package/dist/utils/errors.d.ts.map +1 -1
  24. package/dist/utils/errors.js +10 -2
  25. package/dist/utils/errors.js.map +1 -1
  26. package/dist/utils/port-assignment.d.ts.map +1 -1
  27. package/dist/utils/port-assignment.js +6 -0
  28. package/dist/utils/port-assignment.js.map +1 -1
  29. package/dist/utils/resource-features.d.ts.map +1 -1
  30. package/dist/utils/resource-features.js +12 -0
  31. package/dist/utils/resource-features.js.map +1 -1
  32. package/dist/utils/tilt.d.ts +1 -0
  33. package/dist/utils/tilt.d.ts.map +1 -1
  34. package/dist/utils/tilt.js +2 -1
  35. package/dist/utils/tilt.js.map +1 -1
  36. package/engine/schemas/service-schema.json +20 -0
  37. package/engine/topologies/platform/docker/compose/compose.star +4 -0
  38. package/engine/topologies/platform/docker/compose/traefik_standalone.star +20 -0
  39. package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +4 -1
  40. package/engine/topologies/platform/docker/layers/prisma/prisma_runtime.star +45 -0
  41. package/engine/topologies/platform/docker/networking/sablier_container_cycle.star +25 -23
  42. package/engine/topologies/platform/docker/networking/traefik.star +10 -20
  43. package/engine/topologies/platform/registries/verdaccio_loader.star +18 -0
  44. package/engine/topologies/tilt/manifest/constants.star +1 -0
  45. package/engine/topologies/tilt/manifest/schema.star +29 -1
  46. package/engine/topologies/tilt/manifest/validator.star +1 -1
  47. package/engine/topologies/tilt/resources/infra-loader.star +5 -31
  48. package/package.json +3 -3
@@ -1,27 +1,29 @@
1
- def _sablier_middleware_suffix(manifest):
2
- """Return (middleware_suffix, group, enabled) for a manifest's Sablier block.
1
+ # =============================================================================
2
+ # On-demand scaling: Sablier + Traefik (free-tier stub)
3
+ # =============================================================================
4
+ # Path: engine/topologies/platform/docker/networking/sablier_container_cycle.star
5
+ # =============================================================================
6
+ # The real generator (Sablier + Traefik label wiring that stops idle
7
+ # containers and wakes them on the next request) is part of a paid TDK
8
+ # license. When a valid license grants the "sablier" resource,
9
+ # cli/src/generator/template-engine.ts (vendorTdkExtension) overwrites this
10
+ # file with the licensed version fetched via extension-fetch.ts before Tilt
11
+ # loads it. Same function signatures either way, so nothing else in the
12
+ # generator pipeline changes -- every call site just gets "disabled" back
13
+ # for a manifest's `sablier` block until then.
14
+ # =============================================================================
3
15
 
4
- When a workload opts in via a `sablier` block, it is fronted by the file-provider
5
- middleware `sablier-<group>@file` (defined in the platform proxy dynamic config).
6
- The leading comma lets callers append the suffix to an existing middlewares list.
7
- """
8
- sablier_cfg = manifest.get('sablier', {}) if manifest else {}
9
- if not sablier_cfg.get('enable', False):
10
- return "", "", False
11
- group = sablier_cfg.get('group', manifest.get('stack', '') if manifest else '')
12
- if not group:
13
- return ",sablier-base@file", "", True
14
- return ",sablier-" + group + "@file", group, True
15
16
 
17
+ def _sablier_config(_manifest):
18
+ """Free-tier stub - see module header. Always disabled."""
19
+ return False, "", ""
16
20
 
17
- def _sablier_container_labels(group, indent):
18
- """Container labels that let Sablier discover, wake, and stop this workload.
19
21
 
20
- `traefik.docker.allownonrunning=true` keeps the router registered while the
21
- container is stopped, so the next request can trigger the wake.
22
- """
23
- lines = [indent + '- "sablier.enable=true"']
24
- if group:
25
- lines.append(indent + '- "sablier.group=' + group + '"')
26
- lines.append(indent + '- "traefik.docker.allownonrunning=true"')
27
- return "\n" + "\n".join(lines)
22
+ def _sablier_middleware_suffix(_manifest, _res_name):
23
+ """Free-tier stub - see module header. Always disabled."""
24
+ return "", False
25
+
26
+
27
+ def _sablier_container_labels(_manifest, _res_name, _indent):
28
+ """Free-tier stub - see module header. No labels to add."""
29
+ return ""
@@ -31,21 +31,10 @@ load("./traefik_helpers.star",
31
31
  "get_api_path",
32
32
  "project_backend_rule",
33
33
  )
34
- # load("./sablier_container_cycle.star",
35
- # "_sablier_middleware_suffix",
36
- # "_sablier_container_labels",
37
- # )
38
-
39
- def _sablier_middleware_suffix(_):
40
- # Stub: no Sablier middleware needed
41
- return "", "", False
42
-
43
- def _sablier_container_labels(_, __):
44
- # Stub: no extra labels needed
45
- return ""
46
-
47
-
48
- # Sablier functions imported from sablier_container_cycle.star
34
+ load("./sablier_container_cycle.star",
35
+ "_sablier_middleware_suffix",
36
+ "_sablier_container_labels",
37
+ )
49
38
 
50
39
 
51
40
  def get_frontend_traefik_labels(res_name, domain, base_path, port, traefik_host=None, manifest=None):
@@ -66,7 +55,7 @@ def get_frontend_traefik_labels(res_name, domain, base_path, port, traefik_host=
66
55
  maintenance_middleware = ",maintenance@file"
67
56
 
68
57
  # On-demand scaling: attach the Sablier middleware when opted in via the manifest
69
- sablier_middleware, sablier_group, sablier_enabled = _sablier_middleware_suffix(manifest)
58
+ sablier_middleware, sablier_enabled = _sablier_middleware_suffix(manifest, res_name)
70
59
 
71
60
  labels = """ - "{traefik_enable_label}"
72
61
  - 'traefik.http.routers.{res_name}.rule={frontend_route_rule}'
@@ -90,7 +79,7 @@ def get_frontend_traefik_labels(res_name, domain, base_path, port, traefik_host=
90
79
  )
91
80
 
92
81
  if sablier_enabled:
93
- labels += _sablier_container_labels(sablier_group, " ")
82
+ labels += _sablier_container_labels(manifest, res_name, " ")
94
83
 
95
84
  return labels
96
85
 
@@ -118,7 +107,7 @@ def get_backend_traefik_labels(
118
107
  maintenance_middleware = ",maintenance@file"
119
108
 
120
109
  # On-demand scaling: attach the Sablier middleware when opted in via the manifest
121
- sablier_middleware, sablier_group, sablier_enabled = _sablier_middleware_suffix(manifest)
110
+ sablier_middleware, sablier_enabled = _sablier_middleware_suffix(manifest, resource_entry_name)
122
111
 
123
112
  # Build middleware config only if traefik_path is not empty
124
113
  if traefik_path:
@@ -161,7 +150,7 @@ def get_backend_traefik_labels(
161
150
 
162
151
  # Emit Sablier discovery labels so the Sablier container can wake/stop this workload
163
152
  if sablier_enabled:
164
- labels += _sablier_container_labels(sablier_group, " ")
153
+ labels += _sablier_container_labels(manifest, resource_entry_name, " ")
165
154
 
166
155
  # Generate project localhost routing to match `tdk up` URLs:
167
156
  # http://api.{project}.localhost/api/{resource-name}
@@ -204,7 +193,7 @@ def get_backend_traefik_labels(
204
193
  - "traefik.http.routers.{resource_entry_name}-management.rule=Host(`{api_host}`) && PathPrefix(`{management_path}`)"
205
194
  - "traefik.http.routers.{resource_entry_name}-management.entrypoints={project_entrypoints}"
206
195
  - "traefik.http.routers.{resource_entry_name}-management.service={traefik_resource_name}"
207
- - "traefik.http.routers.{resource_entry_name}-management.middlewares={middleware_name}-management"
196
+ - "traefik.http.routers.{resource_entry_name}-management.middlewares={middleware_name}-management{sablier_middleware}"
208
197
  - "traefik.http.middlewares.{middleware_name}-management.stripprefix.prefixes={management_path}"
209
198
  - "traefik.http.routers.{resource_entry_name}-management.priority={mgmt_priority}"
210
199
  """.format(
@@ -214,6 +203,7 @@ def get_backend_traefik_labels(
214
203
  management_path=management_path,
215
204
  project_entrypoints=project_entrypoints,
216
205
  middleware_name=middleware_name,
206
+ sablier_middleware=sablier_middleware,
217
207
  mgmt_priority=TRAEFIK_FRONTEND_PRIORITY_BASE + len(management_path),
218
208
  )
219
209
 
@@ -0,0 +1,18 @@
1
+ # =============================================================================
2
+ # đŸ“Ļ VERDACCIO (NPM Registry) - loader (free-tier stub)
3
+ # =============================================================================
4
+ # Path: engine/topologies/platform/registries/verdaccio_loader.star
5
+ # =============================================================================
6
+ # The real loader (stands up the Verdaccio private npm registry container and
7
+ # wires it into the project's Docker network) is part of a paid TDK license.
8
+ # When a valid license grants the "verdaccio" resource,
9
+ # cli/src/generator/template-engine.ts (vendorTdkExtension) overwrites this
10
+ # file with the licensed version fetched via extension-fetch.ts before Tilt
11
+ # loads it. Same function signature either way, so nothing else in the
12
+ # loader pipeline changes.
13
+ # =============================================================================
14
+
15
+
16
+ def load_verdaccio(_should_enable, _root_prefix="", _env_file=None):
17
+ """Free-tier stub - see module header. Always skipped."""
18
+ print("â„šī¸ Verdaccio skipped — requires a TDK Premium license (run `tdk upgrade`)")
@@ -69,6 +69,7 @@ VALID_FEATURES = [
69
69
  "env-config",
70
70
  "api-index",
71
71
  "prisma",
72
+ "ddd",
72
73
  # Infrastructure features
73
74
  "nats",
74
75
  "redis",
@@ -8,7 +8,7 @@
8
8
 
9
9
  # === INLINED CONSTANTS for pure extension loading ===
10
10
  VALID_STACKS = () # Stacks are project-specific, discovered dynamically
11
- VALID_FEATURES = "api-client", "env-config", "api-index", "prisma", "nats", "redis", "infisical", "vitest", "traefik", "websocket", "graphql", "grpc", "vite-node", "maintenance"
11
+ VALID_FEATURES = "api-client", "env-config", "api-index", "prisma", "ddd", "nats", "redis", "infisical", "vitest", "traefik", "websocket", "graphql", "grpc", "vite-node", "maintenance", "sablier"
12
12
  PORT_RANGES = {"frontend": {"min": 3000, "max": 5999}, "backend": {"min": 4000, "max": 5999}, "worker": {"min": 6000, "max": 6999}, "migrator": {"min": 7000, "max": 7999}, "sdk": {"min": 3000, "max": 9999}, "library": {"min": 3000, "max": 9999}}
13
13
  RUNTIME = "bun"
14
14
  TRAEFIK_CONFIG = {"entrypoint": "web", "network": "traefik-public", "default_host": "localhost", "default_port": 8080, "tls_enabled": False, "entrypoints": ["web"], "middlewares": [], "tls": {"enabled": False}, "healthcheck_path": "/health", "healthcheck_interval": "10s", "healthcheck_timeout": "5s", "frontend_priority_base": 100}
@@ -252,6 +252,34 @@ MANIFEST_SCHEMA = {
252
252
  },
253
253
  'description': 'Traefik reverse proxy configuration',
254
254
  },
255
+
256
+ # Sablier Configuration (on-demand start/stop for idle resources)
257
+ 'sablier': {
258
+ 'type': 'dict',
259
+ 'required': False,
260
+ 'schema': {
261
+ 'enable': {
262
+ 'type': 'boolean',
263
+ 'required': False,
264
+ 'default': False,
265
+ 'description': 'Scale this resource to zero when idle; Sablier wakes it on the next request',
266
+ },
267
+ 'group': {
268
+ 'type': 'string',
269
+ 'required': False,
270
+ 'description': 'Resources sharing a group wake and sleep together (defaults to `stack`)',
271
+ 'example': 'restaurant',
272
+ },
273
+ 'sessionDuration': {
274
+ 'type': 'string',
275
+ 'required': False,
276
+ 'default': '10m',
277
+ 'description': 'How long the resource stays up after its last request, as a Go duration (e.g. "10m", "1h")',
278
+ 'example': '10m',
279
+ },
280
+ },
281
+ 'description': 'On-demand scaling via Sablier: stop idle containers, wake them on the next request. Not recommended for stateful resources (databases) with in-flight writes. (Premium - requires TDK_LICENSE_KEY; see hasSablierLicense() in extension-fetch.ts)',
282
+ },
255
283
  }
256
284
 
257
285
  # Cross-field validation constraints
@@ -8,7 +8,7 @@
8
8
 
9
9
  # === INLINED CONSTANTS for pure extension loading ===
10
10
  VALID_STACKS = () # Stacks are project-specific, discovered dynamically
11
- VALID_FEATURES = "api-client", "env-config", "api-index", "prisma", "nats", "redis", "infisical", "vitest", "traefik", "websocket", "graphql", "grpc", "vite-node", "maintenance", "sablier"
11
+ VALID_FEATURES = "api-client", "env-config", "api-index", "prisma", "ddd", "nats", "redis", "infisical", "vitest", "traefik", "websocket", "graphql", "grpc", "vite-node", "maintenance", "sablier"
12
12
  PORT_RANGES = {"frontend": {"min": 3000, "max": 5999}, "backend": {"min": 4000, "max": 5999}, "worker": {"min": 6000, "max": 6999}, "migrator": {"min": 7000, "max": 7999}, "sdk": {"min": 3000, "max": 9999}, "library": {"min": 3000, "max": 9999}}
13
13
  DEFAULTS = {}
14
14
 
@@ -20,6 +20,7 @@
20
20
 
21
21
  load("../../platform/docker/constants.star", "PlatformDockerConstants")
22
22
  load("../../platform/docker/compose/traefik_standalone.star", "generate_standalone_traefik_compose")
23
+ load("../../platform/registries/verdaccio_loader.star", "load_verdaccio")
23
24
 
24
25
  # =============================================================================
25
26
  # đŸ—ƒī¸ DATABASE MANAGEMENT
@@ -129,38 +130,11 @@ def _load_database_management(should_enable, root_prefix="", env_file=None, writ
129
130
  # =============================================================================
130
131
  # đŸ“Ļ VERDACCIO (NPM Registry)
131
132
  # =============================================================================
133
+ # Loader lives in ../../platform/registries/verdaccio_loader.star (a free-tier
134
+ # stub in this public repo; the paid CLI overlay swaps it for the real loader
135
+ # — see that module's header comment).
132
136
 
133
- def _load_verdaccio(should_enable, root_prefix="", env_file=None):
134
- """Load Verdaccio private npm registry (premium feature — requires TDK_LICENSE_KEY)."""
135
- # Verdaccio is a premium feature. Skip entirely when no license key is set.
136
- if not os.environ.get("TDK_LICENSE_KEY", ""):
137
- print("â„šī¸ Verdaccio skipped — TDK_LICENSE_KEY not set (premium feature)")
138
- return
139
- if not should_enable(PlatformDockerConstants.VERDACCIO_RESOURCE_NAME):
140
- print("DEBUG INFRA: Verdaccio not enabled")
141
- return
142
-
143
- # Use absolute path for docker-compose to ensure correct working directory
144
- if root_prefix:
145
- compose_file = root_prefix + 'docker-compose.verdaccio.yml'
146
- else:
147
- # Use project root from environment or relative path
148
- project_root = os.environ.get('TDK_PROJECT_ROOT', '.')
149
- compose_file = project_root + '/docker-compose.verdaccio.yml'
150
- if not _file_exists(compose_file):
151
- print("DEBUG INFRA: Skipping Verdaccio (compose file not found)")
152
- return
153
- print("DEBUG INFRA: Loading Verdaccio from {} with env_file={}".format(compose_file, env_file))
154
- _docker_compose(compose_file, env_file)
155
- print("DEBUG INFRA: Calling dc_resource for verdaccio")
156
- dc_resource(PlatformDockerConstants.VERDACCIO_RESOURCE_NAME, labels=['infra.tools', 'registry'], resource_deps=['init-networks'], auto_init=True)
157
- print("DEBUG INFRA: dc_resource for verdaccio completed")
158
- local_resource(PlatformDockerConstants.VERDACCIO_CONNECT_NETWORK_RESOURCE,
159
- cmd='docker network connect ' + PlatformDockerConstants.NETWORK_BACKEND + ' ' + PlatformDockerConstants.VERDACCIO_CONTAINER_NAME + ' 2>/dev/null || true',
160
- labels=['infra.tools', 'registry'],
161
- resource_deps=[PlatformDockerConstants.VERDACCIO_RESOURCE_NAME, 'init-networks'],
162
- auto_init=True
163
- )
137
+ _load_verdaccio = load_verdaccio
164
138
 
165
139
 
166
140
  # =============================================================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tdk-landscape/tdk-cli-core",
3
- "version": "1.3.37",
3
+ "version": "1.3.39",
4
4
  "description": "TDK CLI - Tilt Development Kit command line interface",
5
5
  "keywords": [
6
6
  "tdk",
@@ -43,7 +43,7 @@
43
43
  "build:watch": "tsc --watch",
44
44
  "lint": "biome check .",
45
45
  "lint:fix": "biome check . --write",
46
- "typecheck": "tsc --noEmit",
46
+ "typecheck": "tsc --project tsconfig.typecheck.json",
47
47
  "clean": "rm -rf dist",
48
48
  "dev": "bun run build:watch",
49
49
  "test": "vitest run",
@@ -51,7 +51,6 @@
51
51
  "prepack": "../scripts/stage-npm-engine.sh && npm run build"
52
52
  },
53
53
  "dependencies": {
54
- "@types/react": "^19.2.14",
55
54
  "chalk": "^5.3.0",
56
55
  "commander": "^12.0.0",
57
56
  "handlebars": "^4.7.8",
@@ -62,6 +61,7 @@
62
61
  },
63
62
  "devDependencies": {
64
63
  "@biomejs/biome": "^2.5.13",
64
+ "@types/react": "^19.2.14",
65
65
  "@types/inquirer": "^9.0.0",
66
66
  "@types/node": "^20.0.0",
67
67
  "knip": "^6.35.1",