@zenrows/cli 1.3.1 → 1.3.2

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.
@@ -2,6 +2,9 @@
2
2
  * Toolkit config (`.zenrows/config.json`). Non-secret, safe defaults.
3
3
  */
4
4
  import { randomUUID } from "node:crypto";
5
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { dirname, join } from "node:path";
5
8
  import { findWorkspace, readJson, workspacePaths, writeJson } from "./workspace.js";
6
9
  /** Confirmed Zenrows Fetch and Extract API base. */
7
10
  export const DEFAULT_API_BASE = "https://api.zenrows.com/v1/";
@@ -11,7 +14,7 @@ export const CONFIG_VERSION = "0.1.0";
11
14
  * entrypoint) so core modules — telemetry, signup provenance — can read it
12
15
  * without an import cycle. `VERSION` in `cli/index.ts` re-exports this.
13
16
  */
14
- export const CLI_VERSION = "1.3.1";
17
+ export const CLI_VERSION = "1.3.2";
15
18
  /** The User-Agent on every request to a Zenrows API. The gateway reads the version from it. */
16
19
  export const CLI_USER_AGENT = `zenrows-cli/${CLI_VERSION}`;
17
20
  /** Env var to override the Fetch and Extract API base (local/staging testing). */
@@ -63,21 +66,57 @@ export function saveConfig(config, projectRoot) {
63
66
  const ws = projectRoot ? workspacePaths(projectRoot) : (findWorkspace() ?? workspacePaths());
64
67
  writeJson(ws.config, config);
65
68
  }
69
+ /** Env var to relocate the per-machine config directory (tests, sandboxes). */
70
+ export const CONFIG_HOME_ENV = "ZENROWS_CONFIG_HOME";
71
+ /** Per-machine config directory, shared by every workspace on this machine. */
72
+ export function machineConfigDir() {
73
+ const override = process.env[CONFIG_HOME_ENV];
74
+ if (override && override.trim())
75
+ return override.trim();
76
+ if (process.platform === "win32" && process.env.APPDATA)
77
+ return join(process.env.APPDATA, "zenrows");
78
+ const xdg = process.env.XDG_CONFIG_HOME;
79
+ return join(xdg && xdg.trim() ? xdg.trim() : join(homedir(), ".config"), "zenrows");
80
+ }
81
+ function readMachineTelemetryId(file) {
82
+ try {
83
+ const id = readFileSync(file, "utf8").trim();
84
+ return id || undefined;
85
+ }
86
+ catch {
87
+ return undefined;
88
+ }
89
+ }
66
90
  /**
67
91
  * Return the stable anonymous agent id, generating + persisting one on first
68
92
  * use. Sent as the `X-ZR-Agent-Id` header on signup so the backend can correlate
69
93
  * the (anonymous) device with the account it later merges on claim. Contains no
70
94
  * PII — a random uuid only.
95
+ *
96
+ * Stored per machine, not per workspace: a per-workspace id made every new
97
+ * project folder look like a new device, so the backend could not tell a
98
+ * rate-limited retry from the machine that had just signed up. An id already in
99
+ * the workspace is adopted on first run so existing devices keep their identity.
100
+ * If the machine directory is not writable, falls back to the workspace config.
71
101
  */
72
102
  export function getOrCreateTelemetryId(projectRoot) {
103
+ const file = join(machineConfigDir(), "telemetry-id");
104
+ const machineId = readMachineTelemetryId(file);
105
+ if (machineId)
106
+ return machineId;
73
107
  const ws = projectRoot ? workspacePaths(projectRoot) : (findWorkspace() ?? workspacePaths());
74
108
  // Merge onto the raw stored config (not loadConfig) so we never persist the
75
109
  // ZENROWS_API_BASE env override back into config.json.
76
110
  const stored = readJson(ws.config) ?? {};
77
- const existing = stored.telemetryId;
78
- if (existing && existing.trim())
79
- return existing;
80
- const id = randomUUID();
81
- saveConfig({ ...defaultConfig(), ...stored, telemetryId: id }, projectRoot);
111
+ const workspaceId = stored.telemetryId?.trim() ? stored.telemetryId.trim() : undefined;
112
+ const id = workspaceId ?? randomUUID();
113
+ try {
114
+ mkdirSync(dirname(file), { recursive: true });
115
+ writeFileSync(file, `${id}\n`, { mode: 0o600 });
116
+ }
117
+ catch {
118
+ if (!workspaceId)
119
+ saveConfig({ ...defaultConfig(), ...stored, telemetryId: id }, projectRoot);
120
+ }
82
121
  return id;
83
122
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenrows/cli",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Open-source CLI, MCP, skills, templates, workflows, recipes, and evals layer for giving AI agents reliable access to protected web data through Zenrows cloud infrastructure.",
5
5
  "type": "module",
6
6
  "license": "MIT",