@tdk-landscape/tdk-cli-core 1.3.155 → 1.3.157

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.
@@ -1,2 +1,2 @@
1
1
  import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
2
- import{ub as a,vb as b,wb as c,xb as d,yb as e}from"./chunk-XTSHWDDE.js";import"./chunk-42IVF3YT.js";import"./chunk-6EA4DGCY.js";export{e as assertMachineReadyOrExit,d as formatColdPreflight,a as nodeTooOld,b as requireVerifiedDockerVersions,c as runColdPreflight};
2
+ import{Ib as a,Jb as b,Kb as c,Lb as d,Mb as e}from"./chunk-O2SVXNG5.js";import"./chunk-42IVF3YT.js";import"./chunk-6EA4DGCY.js";export{e as assertMachineReadyOrExit,d as formatColdPreflight,a as nodeTooOld,b as requireVerifiedDockerVersions,c as runColdPreflight};
package/cli/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tdk-cli-internal",
3
3
  "private": true,
4
- "version": "1.3.155",
4
+ "version": "1.3.157",
5
5
  "description": "TDK CLI — start services on your machine.",
6
6
  "keywords": [
7
7
  "tdk",
@@ -218,7 +218,13 @@ def _apply_manifest_defaults(manifest, resource_path):
218
218
  for key, default_value in MANIFEST_DEFAULTS.items():
219
219
  if key not in result or result[key] == None:
220
220
  result[key] = default_value
221
-
221
+
222
+ # A bring-your-own service may not speak HTTP, so only an explicit healthCheckPath gives it one. compose.star and
223
+ # l4_runtime_layers.star read a missing path as "no HTTP probe"; the default above would otherwise hide that.
224
+ # (ManifestParser.normalize applies the same rule, but `tdk up` does not load manifests through it.)
225
+ if result.get('appType') == 'bring-your-own' and not manifest.get('healthCheckPath'):
226
+ result.pop('healthCheckPath', None)
227
+
222
228
  # 🎯 CEO REVIEW: Traefik-native port strategy
223
229
  # Port is constant per appType, not dynamically assigned
224
230
  # Traefik routes by hostname (e.g., booking.backend.{project}.local), not port
@@ -165,9 +165,10 @@ ENV BUN_OPTIONS=--smol
165
165
 
166
166
  USER bun
167
167
 
168
- # Backend-specific healthcheck (checks Bun runtime)
168
+ # Backend-specific healthcheck: probes the service over HTTP. The image is shared by every backend,
169
+ # so the port and path come from the container env (PORT is set by compose, TDK_HEALTH_PATH is optional).
169
170
  HEALTHCHECK {hc_flags} \
170
- CMD bun --version || exit 1
171
+ CMD bun -e "fetch('http://127.0.0.1:'+process.env.PORT+(process.env.TDK_HEALTH_PATH||'/health')).then(r=>process.exit(r.ok?0:1),()=>process.exit(1))" || exit 1
171
172
 
172
173
  WORKDIR /app
173
174
 
@@ -194,9 +195,9 @@ RUN addgroup -S app && adduser -S app -G app
194
195
 
195
196
  USER app
196
197
 
197
- # Backend-specific healthcheck (checks Node.js runtime)
198
+ # Backend-specific healthcheck: probes the service over HTTP (port and path from container env, see the Bun stage)
198
199
  HEALTHCHECK {hc_flags} \
199
- CMD node --version || exit 1
200
+ CMD node -e "fetch('http://127.0.0.1:'+process.env.PORT+(process.env.TDK_HEALTH_PATH||'/health')).then(r=>process.exit(r.ok?0:1),()=>process.exit(1))" || exit 1
200
201
 
201
202
  WORKDIR /app
202
203
 
@@ -14,6 +14,7 @@ BASE_PORT_BACKEND = 4000
14
14
  # emits a fixed `EXPOSE 80` and the generated nginx.conf has a fixed `listen 80`.
15
15
  NGINX_CONTAINER_PORT = 80
16
16
  HEALTH_CHECK_PATH = "/health"
17
+ NO_HTTP_HEALTHCHECK = " healthcheck:\n disable: true\n"
17
18
  OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
18
19
  # === END INLINED CONSTANTS ===
19
20
 
@@ -266,11 +267,14 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
266
267
  restart_policy = manifest.get('restart')
267
268
  restart_policy = '"no"' if restart_policy == 'no' else restart_policy
268
269
 
270
+ # No HTTP server means no HTTP probe. Disable explicitly: the image HEALTHCHECK would otherwise probe a port nothing listens on.
271
+ no_http_healthcheck_section = NO_HTTP_HEALTHCHECK if (is_worker or health_path == None) else ""
272
+ # Backends with a health path get it in the env, so the shared golden image's HEALTHCHECK can probe it.
273
+ health_env = " - TDK_HEALTH_PATH={}\n".format(health_path) if health_path else ""
274
+
269
275
  if is_worker or is_proxy_disabled_byo:
270
276
  traefik_labels = ' - "traefik.enable=false"'
271
- healthcheck_section = "" if is_worker or is_byo else """ healthcheck:
272
- test: ["CMD", "curl", "-f", "--max-time", "5", "http://localhost:{internal_port}{health_path}"]
273
- """.format(internal_port=internal_port, health_path=health_path) + compose_healthcheck_timing()
277
+ healthcheck_section = no_http_healthcheck_section
274
278
  else:
275
279
  # Traefik's load-balancer check can be overridden separately in service.json
276
280
  # (`traefik.healthCheck`); it defaults to the container check's path.
@@ -287,7 +291,7 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
287
291
  # BYO images may not contain curl. Traefik uses its own HTTP health
288
292
  # check labels above, so don't mark an otherwise healthy container
289
293
  # unhealthy because the image lacks a command TDK cannot require.
290
- healthcheck_section = "" if is_byo else """ healthcheck:
294
+ healthcheck_section = no_http_healthcheck_section if no_http_healthcheck_section else "" if is_byo else """ healthcheck:
291
295
  test: ["CMD", "curl", "-f", "--max-time", "5", "http://localhost:{internal_port}{health_path}"]
292
296
  """.format(internal_port=internal_port, health_path=health_path) + compose_healthcheck_timing()
293
297
  infisical_env = get_infisical_environment_vars(as_array=True, resource_name=res_name)
@@ -307,7 +311,7 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
307
311
  {infisical_env}
308
312
  - RESOURCE_NAME={stack}
309
313
  - PORT={port_anchor}
310
- - INSTANCE_ID={instance_label}
314
+ {health_env} - INSTANCE_ID={instance_label}
311
315
  - NATS_QUEUE_GROUP={nats_queue}
312
316
  - TILT_DATABASE_URL={db_url_for_tilt}
313
317
  - TILT_NATS_URL={nats_url}
@@ -363,6 +367,7 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
363
367
  nats_url=nats_url,
364
368
  traefik_labels=traefik_labels,
365
369
  healthcheck_section=healthcheck_section,
370
+ health_env=health_env,
366
371
  infisical_env=infisical_env,
367
372
  auth_env=auth_env,
368
373
  secrets_env=secrets_env,
@@ -4,7 +4,7 @@ OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
4
4
 
5
5
 
6
6
  BUN_BASE = "oven/bun:1.3.11-alpine"
7
- ALPINE_BASE = "alpine:3.18"
7
+ ALPINE_BASE = "alpine:3.22"
8
8
 
9
9
 
10
10
  load('../../../tilt/common/utils.star', 'Utils')
@@ -9,7 +9,7 @@ Provides the foundational layers for all Dockerfiles:
9
9
  """
10
10
 
11
11
  BUN_BASE = "oven/bun:1.3.11-alpine"
12
- ALPINE_BASE = "alpine:3.18"
12
+ ALPINE_BASE = "alpine:3.22"
13
13
  load('../../../../../discovery/config.star', 'GLOBAL_CONFIG')
14
14
 
15
15
  # Load project name for dynamic golden image naming
@@ -2,7 +2,7 @@
2
2
  # SPDX-License-Identifier: MIT
3
3
  # === INLINED CONSTANTS for pure extension loading ===
4
4
  WEB_FRAMEWORK = "hono"
5
- RUNTIME_CONFIG = {"bun": {"image_base": "oven/bun:1.3.11-alpine", "package_manager": "bun", "lockfile": "bun.lock", "backend_start_command": "bun run start", "frontend_start_command": "bun run dev"}, "node": {"image_base": "node:20-alpine", "package_manager": "npm", "lockfile": "package-lock.json", "backend_start_command": "node dist/index.js"}}
5
+ RUNTIME_CONFIG = {"bun": {"image_base": "oven/bun:1.3.11-alpine", "package_manager": "bun", "lockfile": "bun.lock", "backend_start_command": "bun run start", "frontend_start_command": "bun run dev"}, "node": {"image_base": "node:22-alpine", "package_manager": "npm", "lockfile": "package-lock.json", "backend_start_command": "node dist/index.js"}}
6
6
  OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
7
7
  # === END INLINED CONSTANTS ===
8
8
 
@@ -107,6 +107,19 @@ def _cmd_instruction(command):
107
107
  return "CMD [" + ", ".join(["\"" + part + "\"" for part in command.split()]) + "]\n"
108
108
 
109
109
 
110
+ def _backend_healthcheck_instruction(port, manifest = None):
111
+ # Probe the service over HTTP, not the runtime binary: `bun --version` passes even when the server has crashed.
112
+ # Workers and bring-your-own services without healthCheckPath serve no HTTP, so they get no probe (HEALTHCHECK NONE).
113
+ if manifest and (manifest.get('appType') == 'worker' or (manifest.get('appType') == 'bring-your-own' and not manifest.get('healthCheckPath'))):
114
+ return "HEALTHCHECK NONE\n"
115
+ health_path = manifest.get('healthCheckPath', '/health') if manifest else '/health'
116
+ # The Dockerfile generator passes the manifest but not the port, so the service's own port wins over the 4000 default.
117
+ probe_port = manifest.get('port', port) if manifest else port
118
+ # fetch() is built into bun, so no extra package is needed in the image. Path is schema-limited to [a-z0-9/-].
119
+ probe = "fetch('http://127.0.0.1:" + str(probe_port) + health_path + "').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"
120
+ return "HEALTHCHECK " + dockerfile_healthcheck_flags() + " CMD bun -e \"" + probe + "\" || exit 1\n"
121
+
122
+
110
123
  def L4_generate_backend_runtime(res_path, port = BASE_PORT_BACKEND, cmd = 'bun run start', use_infisical = False, resource_name = 'service', use_golden = True, use_prisma = True, has_prisma_config = False, manifest = None):
111
124
  """
112
125
  Generate the backend runtime layer for deployed services.
@@ -174,7 +187,7 @@ def L4_generate_backend_runtime(res_path, port = BASE_PORT_BACKEND, cmd = 'bun r
174
187
 
175
188
  # Only add healthcheck if not using golden image (already in golden L4)
176
189
  if not use_golden:
177
- parts.append("HEALTHCHECK " + dockerfile_healthcheck_flags() + " CMD bun --version || exit 1\n")
190
+ parts.append(_backend_healthcheck_instruction(port, manifest))
178
191
 
179
192
  if use_infisical:
180
193
  # Use InfisicalDocker generator for proper secret injection setup
@@ -202,7 +202,7 @@ RUNTIME_CONFIGS = {
202
202
  'lockfile': 'bun.lock',
203
203
  },
204
204
  'node': {
205
- 'image_base': 'node:20-alpine',
205
+ 'image_base': 'node:22-alpine',
206
206
  'package_manager': 'npm',
207
207
  'lockfile': 'package-lock.json',
208
208
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tdk-landscape/tdk-cli-core",
3
- "version": "1.3.155",
3
+ "version": "1.3.157",
4
4
  "description": "TDK CLI — start services on your machine.",
5
5
  "homepage": "https://tdk-landscape.github.io/tdk-website",
6
6
  "repository": {