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 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 res = await fetchImpl(`${CF_API}${path}`, {
19
- headers: { Authorization: `Bearer ${token}` }
20
- });
21
- let body = null;
29
+ const ctrl = new AbortController();
30
+ const timer = setTimeout(() => ctrl.abort(), API_REQUEST_TIMEOUT_MS);
22
31
  try {
23
- body = await res.json();
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 === 401 || res.status === 403) {
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
- return {
1997
- ok: false,
1998
- reason: `warm ${name} failed: ${err.message}`
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.12";
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."