@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
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tdk-landscape/tdk-cli-core",
|
|
3
|
-
"version": "1.3.
|
|
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": {
|