@lizard-build/cli 0.3.94 → 0.3.95
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/dist/lib/updater.d.ts +1 -1
- package/dist/lib/updater.js +1 -1
- package/dist/lib/wait-ready.d.ts +1 -0
- package/dist/lib/wait-ready.js +11 -3
- package/dist/lib/wait-ready.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/updater.ts +1 -1
- package/src/lib/wait-ready.ts +12 -3
- package/test/unit/wait-ready.test.ts +26 -0
package/dist/lib/updater.d.ts
CHANGED
package/dist/lib/updater.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Readable } from "node:stream";
|
|
|
4
4
|
import { join, dirname } from "node:path";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
|
-
export const CURRENT_VERSION = "0.3.
|
|
7
|
+
export const CURRENT_VERSION = "0.3.95";
|
|
8
8
|
const RELEASES_API = "https://api.github.com/repos/lizard-build/lizard-cli/releases/latest";
|
|
9
9
|
const RELEASE_BASE = "https://github.com/lizard-build/lizard-cli/releases/latest/download";
|
|
10
10
|
/** Minimum gap between background update checks. */
|
package/dist/lib/wait-ready.d.ts
CHANGED
package/dist/lib/wait-ready.js
CHANGED
|
@@ -6,8 +6,10 @@ function sleep(ms) {
|
|
|
6
6
|
* Two consecutive successful checks, spaced apart, against the app's own domain.
|
|
7
7
|
* A single 200 isn't enough during a restart handover — LIZARD-174's reproduction
|
|
8
8
|
* found one healthy response immediately followed by a 502 while the old process
|
|
9
|
-
* was still finishing its shutdown. Not run for
|
|
10
|
-
*
|
|
9
|
+
* was still finishing its shutdown. Not run for containerPort=0 workers —
|
|
10
|
+
* every app gets a generated domain regardless of whether it serves HTTP, so
|
|
11
|
+
* the caller gates this on containerPort, not domain presence (LIZARD-174).
|
|
12
|
+
* Platform-reported readiness is the only signal available for those.
|
|
11
13
|
*/
|
|
12
14
|
async function debounceHealthCheck(domain) {
|
|
13
15
|
for (let i = 0; i < 2; i++) {
|
|
@@ -83,7 +85,13 @@ export async function waitForAppReady(id, baselineRestartedAt, opts = {}) {
|
|
|
83
85
|
return { ok: false, status: app.status, attemptId, domain: app.domain, waitedMs: Date.now() - start };
|
|
84
86
|
}
|
|
85
87
|
if (app.status === "running") {
|
|
86
|
-
|
|
88
|
+
// Every app gets a generated .onlizard.com domain regardless of whether
|
|
89
|
+
// it actually listens for HTTP — a containerPort=0 worker has one too.
|
|
90
|
+
// LIZARD-174: gating on app.domain alone made restart --wait spin a
|
|
91
|
+
// worker until the timeout, health-checking a URL nothing ever answers,
|
|
92
|
+
// even though the platform had already reported it Running/Ready.
|
|
93
|
+
const hasHttpPort = app.containerPort !== 0;
|
|
94
|
+
if (healthCheck && hasHttpPort && app.domain) {
|
|
87
95
|
const healthy = await debounceHealthCheck(app.domain);
|
|
88
96
|
if (!healthy) {
|
|
89
97
|
// Platform says running, but the URL isn't consistently healthy yet
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait-ready.js","sourceRoot":"","sources":["../../src/lib/wait-ready.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"wait-ready.js","sourceRoot":"","sources":["../../src/lib/wait-ready.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lizard-build/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.95",
|
|
4
4
|
"description": "Lizard CLI — deploy apps, databases and sandboxes to Lizard (lizard.build) from your terminal or your coding agent. Detects Go, Node, Python, Rust, Ruby, PHP, Java and static sites; adds Managed Postgres, Managed Redis and Managed Object Storage in one command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/lib/updater.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { join, dirname } from "node:path";
|
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
|
|
8
|
-
export const CURRENT_VERSION = "0.3.
|
|
8
|
+
export const CURRENT_VERSION = "0.3.95";
|
|
9
9
|
const RELEASES_API = "https://api.github.com/repos/lizard-build/lizard-cli/releases/latest";
|
|
10
10
|
const RELEASE_BASE = "https://github.com/lizard-build/lizard-cli/releases/latest/download";
|
|
11
11
|
|
package/src/lib/wait-ready.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface AppSnapshot {
|
|
|
5
5
|
deployStatus?: string | null;
|
|
6
6
|
restartedAt?: number | string | null;
|
|
7
7
|
domain?: string;
|
|
8
|
+
containerPort?: number;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export interface WaitResult {
|
|
@@ -28,8 +29,10 @@ function sleep(ms: number): Promise<void> {
|
|
|
28
29
|
* Two consecutive successful checks, spaced apart, against the app's own domain.
|
|
29
30
|
* A single 200 isn't enough during a restart handover — LIZARD-174's reproduction
|
|
30
31
|
* found one healthy response immediately followed by a 502 while the old process
|
|
31
|
-
* was still finishing its shutdown. Not run for
|
|
32
|
-
*
|
|
32
|
+
* was still finishing its shutdown. Not run for containerPort=0 workers —
|
|
33
|
+
* every app gets a generated domain regardless of whether it serves HTTP, so
|
|
34
|
+
* the caller gates this on containerPort, not domain presence (LIZARD-174).
|
|
35
|
+
* Platform-reported readiness is the only signal available for those.
|
|
33
36
|
*/
|
|
34
37
|
async function debounceHealthCheck(domain: string): Promise<boolean> {
|
|
35
38
|
for (let i = 0; i < 2; i++) {
|
|
@@ -108,7 +111,13 @@ export async function waitForAppReady(
|
|
|
108
111
|
return { ok: false, status: app.status, attemptId, domain: app.domain, waitedMs: Date.now() - start };
|
|
109
112
|
}
|
|
110
113
|
if (app.status === "running") {
|
|
111
|
-
|
|
114
|
+
// Every app gets a generated .onlizard.com domain regardless of whether
|
|
115
|
+
// it actually listens for HTTP — a containerPort=0 worker has one too.
|
|
116
|
+
// LIZARD-174: gating on app.domain alone made restart --wait spin a
|
|
117
|
+
// worker until the timeout, health-checking a URL nothing ever answers,
|
|
118
|
+
// even though the platform had already reported it Running/Ready.
|
|
119
|
+
const hasHttpPort = app.containerPort !== 0;
|
|
120
|
+
if (healthCheck && hasHttpPort && app.domain) {
|
|
112
121
|
const healthy = await debounceHealthCheck(app.domain);
|
|
113
122
|
if (!healthy) {
|
|
114
123
|
// Platform says running, but the URL isn't consistently healthy yet
|
|
@@ -105,6 +105,32 @@ describe("waitForAppReady", () => {
|
|
|
105
105
|
expect(result.ok).toBe(true);
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
+
test("LIZARD-174: a containerPort=0 worker with a domain resolves without health-checking it", async () => {
|
|
109
|
+
// Every app gets a generated .onlizard.com domain regardless of whether it
|
|
110
|
+
// serves HTTP — a worker has one too. Before the fix, healthCheck was gated
|
|
111
|
+
// on domain presence alone, so this spun until timeout fetching a URL
|
|
112
|
+
// nothing ever answers, even though the platform already reported it ready.
|
|
113
|
+
serveSequence([
|
|
114
|
+
{ status: "running", deployStatus: "idle", restartedAt: 2000, domain: "worker.example.test", containerPort: 0 },
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
const realFetch = globalThis.fetch;
|
|
118
|
+
let fetchCalled = false;
|
|
119
|
+
vi.stubGlobal("fetch", (url: string, opts?: any) => {
|
|
120
|
+
if (typeof url === "string" && url.includes("worker.example.test")) fetchCalled = true;
|
|
121
|
+
return realFetch(url, opts);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const result = await waitForAppReady("app1", 1000, { timeoutMs: 4000, healthCheck: true });
|
|
126
|
+
expect(result.ok).toBe(true);
|
|
127
|
+
expect(result.status).toBe("running");
|
|
128
|
+
expect(fetchCalled).toBe(false);
|
|
129
|
+
} finally {
|
|
130
|
+
vi.unstubAllGlobals();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
108
134
|
test("health check debounce: a single 200 mid-handover does not count as ready", async () => {
|
|
109
135
|
serveSequence([{ status: "running", deployStatus: "idle", restartedAt: 2000, domain: "app.example.test" }]);
|
|
110
136
|
|