@tdk-landscape/tdk-cli-core 1.3.77 → 1.3.79

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,8 @@ Notable changes to the `tdk` CLI. Versions match [npm](https://www.npmjs.com/pac
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 1.3.77 (2026-09-30)
8
+
7
9
  - `tdk up` no longer leaves `nats` (and any other service in `services/platform/messaging/docker-compose.yml`, e.g. a local mail catcher) disabled in Tilt. The pre-alpha default always goes through a focus-filter path that only re-enabled `init-networks`/`postgres`/`traefik`/`golden-layers-build`, so a resource with the `nats` feature retried its broker connection forever until you ran `tilt enable nats` by hand. Fixes #155.
8
10
 
9
11
  - `tdk doctor` now catches wiring mistakes that used to surface minutes into `tdk up`: a resource with no `package.json` (the image build stops at "COPY ... not found"), a `params` URL such as `http://auth-emulator:4000` whose port is not the one the target listens on (its `service.json` `port`), a frontend calling a backend through `localhost:<port>` (TDK publishes no backend ports on localhost; use the Traefik route), the `nats` feature without `services/platform/messaging/docker-compose.yml` (TDK does not generate it, so no NATS server starts), two Tilt processes running for one project, and Docker having no address pool left for the networks a project needs. Found while building [tdk-ecommerce-example](https://github.com/tdk-landscape/tdk-ecommerce-example) and a queue/auth example.
@@ -109,6 +109,7 @@ async function fetchPremium(key, resource, projectId) {
109
109
  return fetch(`${url}&key=${encodeURIComponent(key)}`);
110
110
  }
111
111
  async function fetchPremiumBundle(key, projectId) {
112
+ const attempts = [];
112
113
  for (const resource of KNOWN_RESOURCES) {
113
114
  let res;
114
115
  try {
@@ -119,18 +120,23 @@ async function fetchPremiumBundle(key, projectId) {
119
120
  return null;
120
121
  }
121
122
  if (res.ok) {
122
- return Buffer.from(await res.arrayBuffer());
123
+ const bundle = Buffer.from(await res.arrayBuffer());
124
+ console.info(`🔎 Premium entitlement probe: granted resource=${resource} (HTTP ${res.status}); prior denials=${attempts.join(", ") || "none"}`);
125
+ console.info(`🔎 Premium bundle download: ${bundle.byteLength} bytes`);
126
+ return bundle;
123
127
  }
124
128
  if (res.status === 401 || res.status === 403) {
125
129
  // Not granted for this specific resource name - try the next one
126
130
  // before concluding the key has nothing to offer.
131
+ attempts.push(`${resource}=${res.status}`);
127
132
  continue;
128
133
  }
129
134
  // Anything else (404 missing bundle release, 502 upstream failure,
130
135
  // etc.) won't be fixed by trying a different resource name.
131
- console.warn(`⚠️ Premium fetch failed: HTTP ${res.status}`);
136
+ console.warn(`⚠️ Premium fetch failed: ${resource} returned HTTP ${res.status}; prior entitlement probes: ${attempts.join(", ") || "none"}`);
132
137
  return null;
133
138
  }
139
+ console.warn(`⚠️ Premium entitlement probes denied: ${attempts.join(", ")}`);
134
140
  return null;
135
141
  }
136
142
  /**
@@ -146,6 +152,7 @@ export async function applyPremiumOverlay(projectRoot, destDir) {
146
152
  return false;
147
153
  const tarballPath = cacheTarballPath(key);
148
154
  if (!isCacheFresh(tarballPath)) {
155
+ console.info("🔎 Premium bundle cache: miss; requesting bundle from distribution service");
149
156
  const projectId = getOrCreateProjectId(projectRoot);
150
157
  const bundle = await fetchPremiumBundle(key, projectId);
151
158
  if (!bundle) {
@@ -155,20 +162,35 @@ export async function applyPremiumOverlay(projectRoot, destDir) {
155
162
  mkdirSync(join(tarballPath, ".."), { recursive: true });
156
163
  writeFileSync(tarballPath, bundle);
157
164
  }
165
+ else {
166
+ console.info("🔎 Premium bundle cache: hit (cached bundle reused)");
167
+ }
158
168
  try {
159
169
  const extractDir = join(tarballPath, "..", "extracted");
160
170
  mkdirSync(extractDir, { recursive: true });
161
171
  extractTarball(readFileSync(tarballPath), extractDir);
162
172
  let applied = 0;
173
+ const missing = [];
163
174
  for (const [src, dest] of Object.entries(PREMIUM_PATH_MAP)) {
164
175
  const from = join(extractDir, src);
165
- if (!existsSync(from))
176
+ if (!existsSync(from)) {
177
+ missing.push(src);
166
178
  continue;
179
+ }
167
180
  const to = join(destDir, dest);
168
181
  mkdirSync(join(to, ".."), { recursive: true });
169
182
  writeFileSync(to, readFileSync(from));
170
183
  applied++;
171
184
  }
185
+ const sablierPath = join(extractDir, "networking/sablier_container_cycle.star");
186
+ console.info(`🔎 Premium bundle contents: mapped=${applied}/${Object.keys(PREMIUM_PATH_MAP).length}; sablier_overlay=${existsSync(sablierPath) ? "present" : "MISSING"}`);
187
+ if (missing.length > 0) {
188
+ console.info(`🔎 Premium bundle missing mapped files: ${missing.join(", ")}`);
189
+ }
190
+ if (!existsSync(sablierPath) && process.env.TDK_PREMIUM_DIAGNOSTICS === "1") {
191
+ const sablierGranted = await hasSablierLicense(projectRoot);
192
+ console.info(`🔎 Sablier entitlement check: ${sablierGranted ? "granted" : "not confirmed"}; compare with sablier_overlay above to distinguish license access from bundle contents`);
193
+ }
172
194
  if (applied > 0) {
173
195
  console.log(`✓ Premium resources unlocked (${applied} file${applied === 1 ? "" : "s"})`);
174
196
  return true;
@@ -211,6 +233,7 @@ async function hasLiveResourceLicense(projectRoot, resource) {
211
233
  if (isCacheFresh(cachePath)) {
212
234
  try {
213
235
  const cached = JSON.parse(readFileSync(cachePath, "utf-8"));
236
+ console.info(`🔎 ${resource} entitlement probe: cache=${cached.granted === true ? "granted" : "denied"}`);
214
237
  return cached.granted === true;
215
238
  }
216
239
  catch {
@@ -222,6 +245,7 @@ async function hasLiveResourceLicense(projectRoot, resource) {
222
245
  try {
223
246
  const res = await fetchPremium(key, resource, projectId);
224
247
  granted = res.ok;
248
+ console.info(`🔎 ${resource} entitlement probe: HTTP ${res.status} (${granted ? "granted" : "denied"})`);
225
249
  // Drain the body (a full premium.tar.gz on success) so we don't leave
226
250
  // it dangling - we only need the status, not the content.
227
251
  if (res.body) {
@@ -376,10 +376,22 @@ function probeAddress(port, host) {
376
376
  * it before trying 127.0.0.1 avoids that self-collision on every platform.
377
377
  */
378
378
  export async function probeHostPort(port) {
379
- const wildcard = await probeAddress(port, "0.0.0.0");
380
- if (wildcard !== "free")
381
- return wildcard;
382
- return probeAddress(port, "127.0.0.1");
379
+ // Several `tdk project` E2E tests can run at once. Their preflight probes
380
+ // briefly bind the same port, so an EADDRINUSE can be another probe rather
381
+ // than a service. Retry once after those short-lived binds have closed.
382
+ for (let attempt = 0; attempt < 2; attempt++) {
383
+ const wildcard = await probeAddress(port, "0.0.0.0");
384
+ if (wildcard === "unknown")
385
+ return wildcard;
386
+ if (wildcard === "free") {
387
+ const loopback = await probeAddress(port, "127.0.0.1");
388
+ if (loopback === "free" || loopback === "unknown")
389
+ return loopback;
390
+ }
391
+ if (attempt === 0)
392
+ await new Promise((resolve) => setTimeout(resolve, 50));
393
+ }
394
+ return "in-use";
383
395
  }
384
396
  /** What an HTTP status from a service's health URL means, in the words a user needs. */
385
397
  function describeProbeFailure(probe) {
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.77",
4
+ "version": "1.3.79",
5
5
  "description": "TDK CLI - Tilt Development Kit command line interface",
6
6
  "keywords": [
7
7
  "tdk",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tdk-landscape/tdk-cli-core",
3
- "version": "1.3.77",
3
+ "version": "1.3.79",
4
4
  "description": "Run your whole microservice landscape locally without Kubernetes. Scaffold services and run them with hot reload, built on Tilt.",
5
5
  "homepage": "https://tdk-landscape.github.io/tdk-website",
6
6
  "repository": {