@tiny-fish/cli 0.8.0 → 0.8.1-next.121

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.
@@ -138,9 +138,38 @@ const OPENCLAW = {
138
138
  unavailableMessage: OPENCLAW_SKILL_UNAVAILABLE_MESSAGE,
139
139
  },
140
140
  };
141
- function createConnectTelemetry(mcpUrl, client) {
141
+ // TinyFish-owned domains plus loopback are the only origins the API key may be sent to.
142
+ // `--url` accepts any http(s) URL, so a user-supplied origin must never receive the key.
143
+ const TRUSTED_TELEMETRY_HOST_SUFFIXES = [".tinyfish.ai", ".tinyfish.io"];
144
+ const TRUSTED_TELEMETRY_LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "[::1]"];
145
+ function isTrustedTelemetryOrigin(endpoint) {
146
+ let url;
147
+ try {
148
+ url = new URL(endpoint);
149
+ }
150
+ catch {
151
+ return false;
152
+ }
153
+ const host = url.hostname.toLowerCase();
154
+ // Loopback may use http for local dev; every other trusted origin must be https so the
155
+ // key is never sent over cleartext.
156
+ if (TRUSTED_TELEMETRY_LOOPBACK_HOSTS.includes(host))
157
+ return true;
158
+ if (url.protocol !== "https:")
159
+ return false;
160
+ return TRUSTED_TELEMETRY_HOST_SUFFIXES.some((suffix) => host === suffix.slice(1) || host.endsWith(suffix));
161
+ }
162
+ function createConnectTelemetry(mcpUrl, client, apiKey) {
142
163
  const attemptId = randomUUID();
143
164
  const endpoint = new URL("/api/cli/connect-event", mcpUrl).toString();
165
+ const telemetryKey = apiKey ?? process.env["TINYFISH_API_KEY"];
166
+ const headers = { "content-type": "application/json" };
167
+ // Attach the key so the endpoint can attribute the event to the signed-in user, but only
168
+ // when it is well-formed AND the endpoint is a trusted TinyFish origin. A user-supplied
169
+ // --url pointing elsewhere gets anonymous telemetry, never the key.
170
+ if (telemetryKey && validateKeyFormat(telemetryKey) && isTrustedTelemetryOrigin(endpoint)) {
171
+ headers["x-api-key"] = telemetryKey;
172
+ }
144
173
  let enabled = true;
145
174
  return {
146
175
  attemptId,
@@ -150,7 +179,7 @@ function createConnectTelemetry(mcpUrl, client) {
150
179
  try {
151
180
  const response = await fetch(endpoint, {
152
181
  method: "POST",
153
- headers: { "content-type": "application/json" },
182
+ headers,
154
183
  body: JSON.stringify({
155
184
  attempt_id: attemptId,
156
185
  client,
@@ -309,7 +338,7 @@ function launchOpenClawWalkthrough() {
309
338
  return true;
310
339
  }
311
340
  async function connectNativeMcpClient(client, options) {
312
- const telemetry = createConnectTelemetry(options.mcpUrl, client.connectClient);
341
+ const telemetry = createConnectTelemetry(options.mcpUrl, client.connectClient, options.apiKey);
313
342
  let failureStage = "prerequisite_check";
314
343
  try {
315
344
  await telemetry.track("started");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-fish/cli",
3
- "version": "0.8.0",
3
+ "version": "0.8.1-next.121",
4
4
  "description": "TinyFish CLI — run web automations from your terminal",
5
5
  "type": "module",
6
6
  "bin": {