create-op-node 0.10.12 → 0.10.14
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/cli.js +54 -25
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,18 +12,38 @@ import { readFileSync } from 'fs';
|
|
|
12
12
|
import * as tls from 'tls';
|
|
13
13
|
import { Validator } from '@cfworker/json-schema';
|
|
14
14
|
|
|
15
|
+
// src/lib/constants.ts
|
|
16
|
+
var PGSODIUM_KEY_RE = /^[a-f0-9]{64}$/;
|
|
17
|
+
var TUNNEL_TOKEN_RE = /^[A-Za-z0-9_\-.=]+$/;
|
|
18
|
+
var SAFE_PATH_RE = /^[A-Za-z0-9_\-./ ]+$/;
|
|
19
|
+
var SAFE_LAUNCHCTL_VALUE_RE = /^[A-Za-z0-9+/=._-]+$/;
|
|
20
|
+
var URL_SAFE_PASSWORD_RE = /^[A-Za-z0-9_-]+$/;
|
|
21
|
+
var SAFE_URL_RE = /^[A-Za-z0-9:/_.-]+$/;
|
|
22
|
+
var VERIFY_NETWORK_TIMEOUT_MS = 1e4;
|
|
23
|
+
var API_REQUEST_TIMEOUT_MS = 15e3;
|
|
24
|
+
var BODY_PREVIEW_MAX = 200;
|
|
25
|
+
|
|
15
26
|
// src/lib/cloudflare.ts
|
|
16
27
|
var CF_API = "https://api.cloudflare.com/client/v4";
|
|
17
28
|
async function get(token, path, fetchImpl = fetch) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
let body = null;
|
|
29
|
+
const ctrl = new AbortController();
|
|
30
|
+
const timer = setTimeout(() => ctrl.abort(), API_REQUEST_TIMEOUT_MS);
|
|
22
31
|
try {
|
|
23
|
-
|
|
32
|
+
const res = await fetchImpl(`${CF_API}${path}`, {
|
|
33
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
34
|
+
signal: ctrl.signal
|
|
35
|
+
});
|
|
36
|
+
let body = null;
|
|
37
|
+
try {
|
|
38
|
+
body = await res.json();
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
return { status: res.status, body };
|
|
24
42
|
} catch {
|
|
43
|
+
return { status: 0, body: null };
|
|
44
|
+
} finally {
|
|
45
|
+
clearTimeout(timer);
|
|
25
46
|
}
|
|
26
|
-
return { status: res.status, body };
|
|
27
47
|
}
|
|
28
48
|
function shortError(body) {
|
|
29
49
|
if (typeof body === "object" && body !== null && "errors" in body && Array.isArray(body.errors)) {
|
|
@@ -38,6 +58,12 @@ function shortError(body) {
|
|
|
38
58
|
async function probeCloudflareToken(input) {
|
|
39
59
|
const issues = [];
|
|
40
60
|
const verify = await get(input.token, `/accounts/${input.accountId}/tokens/verify`);
|
|
61
|
+
if (verify.status === 0) {
|
|
62
|
+
issues.push(
|
|
63
|
+
"Couldn't reach Cloudflare (network error or timeout). Check your connection and retry."
|
|
64
|
+
);
|
|
65
|
+
return { ok: false, issues };
|
|
66
|
+
}
|
|
41
67
|
if (verify.status !== 200) {
|
|
42
68
|
issues.push(
|
|
43
69
|
`Token verify failed (HTTP ${verify.status}): ${shortError(verify.body)}`
|
|
@@ -55,7 +81,9 @@ async function probeCloudflareToken(input) {
|
|
|
55
81
|
const res = await get(input.token, check.path);
|
|
56
82
|
if (res.status === 200) continue;
|
|
57
83
|
if (res.status === 404 && check.treat404AsPass) continue;
|
|
58
|
-
if (res.status ===
|
|
84
|
+
if (res.status === 0) {
|
|
85
|
+
issues.push(`Couldn't reach Cloudflare while checking ${check.name} (network error or timeout).`);
|
|
86
|
+
} else if (res.status === 401 || res.status === 403) {
|
|
59
87
|
issues.push(`Missing scope: ${check.name}`);
|
|
60
88
|
} else if (res.status === 400 && typeof res.body === "object" && res.body !== null && "errors" in res.body && Array.isArray(res.body.errors) && res.body.errors.some((e) => e.code === 10042)) {
|
|
61
89
|
issues.push(
|
|
@@ -75,6 +103,9 @@ async function tunnelStatus(input) {
|
|
|
75
103
|
`/accounts/${input.accountId}/cfd_tunnel/${input.tunnelId}`,
|
|
76
104
|
fetchImpl
|
|
77
105
|
);
|
|
106
|
+
if (res.status === 0) {
|
|
107
|
+
return { ok: false, reason: "couldn't reach Cloudflare (network error or timeout)" };
|
|
108
|
+
}
|
|
78
109
|
if (res.status !== 200) {
|
|
79
110
|
return {
|
|
80
111
|
ok: false,
|
|
@@ -90,17 +121,6 @@ async function tunnelStatus(input) {
|
|
|
90
121
|
}
|
|
91
122
|
}
|
|
92
123
|
|
|
93
|
-
// src/lib/constants.ts
|
|
94
|
-
var PGSODIUM_KEY_RE = /^[a-f0-9]{64}$/;
|
|
95
|
-
var TUNNEL_TOKEN_RE = /^[A-Za-z0-9_\-.=]+$/;
|
|
96
|
-
var SAFE_PATH_RE = /^[A-Za-z0-9_\-./ ]+$/;
|
|
97
|
-
var SAFE_LAUNCHCTL_VALUE_RE = /^[A-Za-z0-9+/=._-]+$/;
|
|
98
|
-
var URL_SAFE_PASSWORD_RE = /^[A-Za-z0-9_-]+$/;
|
|
99
|
-
var SAFE_URL_RE = /^[A-Za-z0-9:/_.-]+$/;
|
|
100
|
-
var VERIFY_NETWORK_TIMEOUT_MS = 1e4;
|
|
101
|
-
var API_REQUEST_TIMEOUT_MS = 15e3;
|
|
102
|
-
var BODY_PREVIEW_MAX = 200;
|
|
103
|
-
|
|
104
124
|
// src/lib/tfc.ts
|
|
105
125
|
var TFC_API = "https://app.terraform.io/api/v2";
|
|
106
126
|
var ORG_SLUG_RE = /^[A-Za-z0-9_-]{1,40}$/;
|
|
@@ -1940,6 +1960,8 @@ function assessAllRunning(snapshots) {
|
|
|
1940
1960
|
|
|
1941
1961
|
// src/lib/ollama.ts
|
|
1942
1962
|
var OLLAMA_URL = "http://localhost:11434";
|
|
1963
|
+
var OLLAMA_HEALTH_TIMEOUT_MS = 5e3;
|
|
1964
|
+
var OLLAMA_WARM_TIMEOUT_MS = 12e4;
|
|
1943
1965
|
var DEFAULT_LLM_MODEL = "qwen3.5:9b";
|
|
1944
1966
|
var DEFAULT_EMBEDDING_MODEL = "nomic-embed-text";
|
|
1945
1967
|
var PROBE_ALPINE_TAG = "3.20";
|
|
@@ -1955,14 +1977,18 @@ async function startOllamaService() {
|
|
|
1955
1977
|
return { ok: true };
|
|
1956
1978
|
}
|
|
1957
1979
|
async function checkOllamaHealth(url = OLLAMA_URL) {
|
|
1980
|
+
const ctrl = new AbortController();
|
|
1981
|
+
const timer = setTimeout(() => ctrl.abort(), OLLAMA_HEALTH_TIMEOUT_MS);
|
|
1958
1982
|
try {
|
|
1959
|
-
const res = await fetch(`${url}/api/tags
|
|
1983
|
+
const res = await fetch(`${url}/api/tags`, { signal: ctrl.signal });
|
|
1960
1984
|
if (!res.ok) return { reachable: false, models: [] };
|
|
1961
1985
|
const body = await res.json();
|
|
1962
1986
|
const models = (body.models ?? []).map((m) => m.name ?? "").filter((n) => n.length > 0);
|
|
1963
1987
|
return { reachable: true, models };
|
|
1964
1988
|
} catch {
|
|
1965
1989
|
return { reachable: false, models: [] };
|
|
1990
|
+
} finally {
|
|
1991
|
+
clearTimeout(timer);
|
|
1966
1992
|
}
|
|
1967
1993
|
}
|
|
1968
1994
|
async function pullModel(name) {
|
|
@@ -1977,11 +2003,14 @@ async function pullModel(name) {
|
|
|
1977
2003
|
return { ok: true };
|
|
1978
2004
|
}
|
|
1979
2005
|
async function warmModel(name, url = OLLAMA_URL) {
|
|
2006
|
+
const ctrl = new AbortController();
|
|
2007
|
+
const timer = setTimeout(() => ctrl.abort(), OLLAMA_WARM_TIMEOUT_MS);
|
|
1980
2008
|
try {
|
|
1981
2009
|
const res = await fetch(`${url}/api/generate`, {
|
|
1982
2010
|
method: "POST",
|
|
1983
2011
|
headers: { "Content-Type": "application/json" },
|
|
1984
|
-
body: JSON.stringify({ model: name, prompt: "hi", stream: false })
|
|
2012
|
+
body: JSON.stringify({ model: name, prompt: "hi", stream: false }),
|
|
2013
|
+
signal: ctrl.signal
|
|
1985
2014
|
});
|
|
1986
2015
|
if (!res.ok) {
|
|
1987
2016
|
const text6 = await res.text().catch(() => "");
|
|
@@ -1993,10 +2022,10 @@ async function warmModel(name, url = OLLAMA_URL) {
|
|
|
1993
2022
|
await res.text();
|
|
1994
2023
|
return { ok: true };
|
|
1995
2024
|
} catch (err) {
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2025
|
+
const reason = err.name === "AbortError" ? `warm ${name} timed out after ${OLLAMA_WARM_TIMEOUT_MS / 1e3}s` : `warm ${name} failed: ${err.message}`;
|
|
2026
|
+
return { ok: false, reason };
|
|
2027
|
+
} finally {
|
|
2028
|
+
clearTimeout(timer);
|
|
2000
2029
|
}
|
|
2001
2030
|
}
|
|
2002
2031
|
async function probeHostDockerInternal() {
|
|
@@ -4831,7 +4860,7 @@ async function looksLikeRegionsRepo(dir) {
|
|
|
4831
4860
|
}
|
|
4832
4861
|
|
|
4833
4862
|
// src/cli.ts
|
|
4834
|
-
var VERSION = "0.10.
|
|
4863
|
+
var VERSION = "0.10.14";
|
|
4835
4864
|
var program = new Command();
|
|
4836
4865
|
program.name("create-op-node").description(
|
|
4837
4866
|
"Interactive bootstrap for an Opus Populi federation node.\nCloudflare infrastructure \u2192 Mac Studio \u2192 live public API."
|