@farm.js/cli 0.1.0-beta.52 → 0.1.0-beta.54

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/index.js CHANGED
@@ -3317,6 +3317,7 @@ exports.migrateFarmAuth = migrateFarmAuth;
3317
3317
  exports.parsePreviewPublicUrl = parsePreviewPublicUrl;
3318
3318
  exports.previewFarm = previewFarm;
3319
3319
  exports.resolveCloudflareAgentDeployPlan = resolveCloudflareAgentDeployPlan;
3320
+ exports.resolveFarmCreateAppTelemetryCommand = require_telemetry.resolveFarmCreateAppTelemetryCommand;
3320
3321
  exports.resolveFarmTelemetryCommand = require_telemetry.resolveFarmTelemetryCommand;
3321
3322
  exports.resolvePreviewTarget = resolvePreviewTarget;
3322
3323
  exports.runFarmCronJob = runFarmCronJob;
@@ -3333,6 +3334,7 @@ Object.defineProperty(exports, "startDevServer", {
3333
3334
  });
3334
3335
  exports.startFarmCronScheduler = startFarmCronScheduler;
3335
3336
  exports.trackFarmCommand = require_telemetry.trackFarmCommand;
3337
+ exports.trackFarmCreateAppCommand = require_telemetry.trackFarmCreateAppCommand;
3336
3338
  exports.trackFarmProjectCreated = require_telemetry.trackFarmProjectCreated;
3337
3339
  exports.upgradeFarm = upgradeFarm;
3338
3340
 
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as listFarmIntegrationProviders, t as addFarmIntegration } from "./add-integration-7hf9WI7e.mjs";
2
2
  import { buildFarm } from "./build.mjs";
3
- import { getFarmTelemetryConfigFile, getFarmTelemetryStatus, resolveFarmTelemetryCommand, setFarmTelemetryEnabled, showFarmTelemetryNotice, trackFarmCommand, trackFarmProjectCreated } from "./telemetry.mjs";
3
+ import { getFarmTelemetryConfigFile, getFarmTelemetryStatus, resolveFarmCreateAppTelemetryCommand, resolveFarmTelemetryCommand, setFarmTelemetryEnabled, showFarmTelemetryNotice, trackFarmCommand, trackFarmCreateAppCommand, trackFarmProjectCreated } from "./telemetry.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { createServer, startDevServer } from "@farm.js/core/server";
6
6
  import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs";
@@ -3278,6 +3278,6 @@ function formatError(error) {
3278
3278
  return error instanceof Error ? error.message : String(error);
3279
3279
  }
3280
3280
  //#endregion
3281
- export { FarmDeployError, FarmGeneratedArtifactsStaleError, addFarmIntegration, buildFarm, createFarmDeployPlan, createFarmUpgradePlan, createFrameworkMigrationPlan, createGatewaySession, createPreviewGatewayPlan, createPreviewTunnelPlan, createServer, deployFarm, detectFarmPackageManager, explainFarmRoute, formatFarmCronJobs, formatFarmDeployPlan, formatFarmDoctorReport, formatFarmRouteExplanation, formatFarmUpgradePlan, forwardGatewayRequest, generateFarmArtifacts, getFarmTelemetryConfigFile, getFarmTelemetryStatus, inspectFrameworkMigrations, listFarmCronJobs, listFarmIntegrationProviders, loadFarmCronConfig, migrateFarm, migrateFarmAuth, parsePreviewPublicUrl, previewFarm, resolveCloudflareAgentDeployPlan, resolveFarmTelemetryCommand, resolvePreviewTarget, runFarmCronJob, runFarmDoctor, runNativePreviewTunnel, runPreviewGateway, setFarmTelemetryEnabled, showFarmTelemetryNotice, startDevServer, startFarmCronScheduler, trackFarmCommand, trackFarmProjectCreated, upgradeFarm };
3281
+ export { FarmDeployError, FarmGeneratedArtifactsStaleError, addFarmIntegration, buildFarm, createFarmDeployPlan, createFarmUpgradePlan, createFrameworkMigrationPlan, createGatewaySession, createPreviewGatewayPlan, createPreviewTunnelPlan, createServer, deployFarm, detectFarmPackageManager, explainFarmRoute, formatFarmCronJobs, formatFarmDeployPlan, formatFarmDoctorReport, formatFarmRouteExplanation, formatFarmUpgradePlan, forwardGatewayRequest, generateFarmArtifacts, getFarmTelemetryConfigFile, getFarmTelemetryStatus, inspectFrameworkMigrations, listFarmCronJobs, listFarmIntegrationProviders, loadFarmCronConfig, migrateFarm, migrateFarmAuth, parsePreviewPublicUrl, previewFarm, resolveCloudflareAgentDeployPlan, resolveFarmCreateAppTelemetryCommand, resolveFarmTelemetryCommand, resolvePreviewTarget, runFarmCronJob, runFarmDoctor, runNativePreviewTunnel, runPreviewGateway, setFarmTelemetryEnabled, showFarmTelemetryNotice, startDevServer, startFarmCronScheduler, trackFarmCommand, trackFarmCreateAppCommand, trackFarmProjectCreated, upgradeFarm };
3282
3282
 
3283
3283
  //# sourceMappingURL=index.mjs.map
package/dist/telemetry.js CHANGED
@@ -26,6 +26,7 @@ const FARM_COMMANDS = [
26
26
  "add:integration",
27
27
  "deploy"
28
28
  ];
29
+ const CREATE_APP_COMMANDS = ["create", "list-templates"];
29
30
  const FARM_TEMPLATES = [
30
31
  "basic",
31
32
  "react-compiler",
@@ -258,6 +259,9 @@ async function showFarmTelemetryNotice() {
258
259
  function resolveFarmTelemetryCommand(value) {
259
260
  return FARM_COMMANDS.includes(value) ? value : void 0;
260
261
  }
262
+ function resolveFarmCreateAppTelemetryCommand(value) {
263
+ return CREATE_APP_COMMANDS.includes(value) ? value : void 0;
264
+ }
261
265
  async function trackFarmCommand(input) {
262
266
  const deployTarget = allowlisted(input.deployTarget, DEPLOY_TARGETS);
263
267
  await track({
@@ -269,6 +273,17 @@ async function trackFarmCommand(input) {
269
273
  ...deployTarget ? { deployTarget } : {}
270
274
  });
271
275
  }
276
+ async function trackFarmCreateAppCommand(input) {
277
+ const command = allowlisted(input.command, CREATE_APP_COMMANDS);
278
+ if (!command) return;
279
+ await track({
280
+ eventType: "command_invoked",
281
+ source: "create-app",
282
+ packageName: "@farm.js/create-app",
283
+ packageVersion: sanitizeVersion(input.packageVersion),
284
+ command
285
+ });
286
+ }
272
287
  async function trackFarmProjectCreated(input) {
273
288
  const template = allowlisted(input.template, FARM_TEMPLATES);
274
289
  const renderer = allowlisted(input.renderer, RENDERERS);
@@ -338,10 +353,12 @@ function normalizeArchitecture(value) {
338
353
  //#endregion
339
354
  exports.getFarmTelemetryConfigFile = getFarmTelemetryConfigFile;
340
355
  exports.getFarmTelemetryStatus = getFarmTelemetryStatus;
356
+ exports.resolveFarmCreateAppTelemetryCommand = resolveFarmCreateAppTelemetryCommand;
341
357
  exports.resolveFarmTelemetryCommand = resolveFarmTelemetryCommand;
342
358
  exports.setFarmTelemetryEnabled = setFarmTelemetryEnabled;
343
359
  exports.showFarmTelemetryNotice = showFarmTelemetryNotice;
344
360
  exports.trackFarmCommand = trackFarmCommand;
361
+ exports.trackFarmCreateAppCommand = trackFarmCreateAppCommand;
345
362
  exports.trackFarmProjectCreated = trackFarmProjectCreated;
346
363
 
347
364
  //# sourceMappingURL=telemetry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.js","names":["path","os","readFile","randomUUID","mkdir","writeFile","rename","chmod","unlink"],"sources":["../src/telemetry.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { chmod, mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst TELEMETRY_SCHEMA_VERSION = 1 as const;\nconst DEFAULT_TELEMETRY_ENDPOINT = \"https://farmjs.dev/api/telemetry/v1/events\";\nconst TELEMETRY_NOTICE_URL = \"https://farmjs.dev/docs/telemetry\";\nconst REQUEST_TIMEOUT_MS = 750;\n\nconst FARM_COMMANDS = [\n \"dev\",\n \"build\",\n \"auth:migrate\",\n \"upgrade\",\n \"generate\",\n \"doctor\",\n \"explain\",\n \"preview\",\n \"migrate\",\n \"cron:list\",\n \"cron:run\",\n \"add:integration\",\n \"deploy\",\n] as const;\n\nconst FARM_TEMPLATES = [\n \"basic\",\n \"react-compiler\",\n \"auth\",\n \"better-auth\",\n \"ai\",\n \"auth0\",\n \"authjs\",\n \"autumn\",\n \"clerk\",\n \"jobs-inngest\",\n \"jobs-trigger\",\n \"polar\",\n \"resend\",\n \"stripe\",\n \"supabase\",\n \"unkey\",\n \"workos\",\n] as const;\n\nconst RENDERERS = [\"react\", \"preact\", \"solid\", \"vue\", \"svelte\"] as const;\nconst PACKAGE_MANAGERS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const;\nconst DEPLOY_TARGETS = [\"vercel\", \"cloudflare\", \"netlify\", \"node\", \"custom\"] as const;\n\nexport type FarmTelemetryCommand = (typeof FARM_COMMANDS)[number];\nexport type FarmTelemetryTemplate = (typeof FARM_TEMPLATES)[number];\nexport type FarmTelemetryRenderer = (typeof RENDERERS)[number];\nexport type FarmTelemetryPackageManager = (typeof PACKAGE_MANAGERS)[number];\nexport type FarmTelemetryDeployTarget = (typeof DEPLOY_TARGETS)[number];\n\ninterface FarmTelemetryConfig {\n version: 1;\n enabled: boolean;\n noticeShown: boolean;\n anonymousId?: string;\n}\n\ninterface FarmTelemetryConfigState {\n config: FarmTelemetryConfig;\n stored: boolean;\n}\n\ninterface FarmTelemetryEventBase {\n schemaVersion: typeof TELEMETRY_SCHEMA_VERSION;\n eventId: string;\n anonymousId: string;\n source: \"cli\" | \"create-app\";\n packageName: \"@farm.js/cli\" | \"@farm.js/create-app\";\n packageVersion: string;\n nodeMajor: number;\n platform: \"darwin\" | \"linux\" | \"windows\" | \"other\";\n architecture: \"arm64\" | \"x64\" | \"other\";\n}\n\nexport interface FarmCommandTelemetryInput {\n command: FarmTelemetryCommand;\n packageVersion: string;\n deployTarget?: string;\n}\n\nexport interface FarmProjectCreatedTelemetryInput {\n packageVersion: string;\n template?: string;\n renderer?: string;\n packageManager?: string;\n typescript?: boolean;\n installedDependencies?: boolean;\n}\n\nexport interface FarmTelemetryStatus {\n enabled: boolean;\n active: boolean;\n source: \"configuration\" | \"environment\" | \"default\";\n endpoint: string;\n configFile: string;\n anonymousId?: string;\n reason?: string;\n}\n\ntype FarmTelemetryEvent =\n | (FarmTelemetryEventBase & {\n eventType: \"command_invoked\";\n command: FarmTelemetryCommand;\n deployTarget?: FarmTelemetryDeployTarget;\n })\n | (FarmTelemetryEventBase & {\n eventType: \"project_created\";\n template?: FarmTelemetryTemplate;\n renderer?: FarmTelemetryRenderer;\n packageManager?: FarmTelemetryPackageManager;\n typescript?: boolean;\n installedDependencies?: boolean;\n });\n\ntype FarmTelemetryGeneratedFields = Pick<\n FarmTelemetryEventBase,\n \"schemaVersion\" | \"eventId\" | \"anonymousId\" | \"nodeMajor\" | \"platform\" | \"architecture\"\n>;\ntype FarmTelemetryEventInput<T = FarmTelemetryEvent> = T extends FarmTelemetryEvent\n ? Omit<T, keyof FarmTelemetryGeneratedFields>\n : never;\n\nfunction defaultConfig(): FarmTelemetryConfig {\n return {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: true,\n noticeShown: false,\n };\n}\n\nfunction configDirectory(): string {\n if (process.env.FARM_TELEMETRY_CONFIG_DIR) {\n return path.resolve(process.env.FARM_TELEMETRY_CONFIG_DIR);\n }\n if (process.platform === \"win32\") {\n return path.join(\n process.env.APPDATA || path.join(os.homedir(), \"AppData\", \"Roaming\"),\n \"farmjs\",\n );\n }\n if (process.platform === \"darwin\") {\n return path.join(os.homedir(), \"Library\", \"Application Support\", \"farmjs\");\n }\n return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), \".config\"), \"farmjs\");\n}\n\nexport function getFarmTelemetryConfigFile(): string {\n return path.join(configDirectory(), \"telemetry.json\");\n}\n\nasync function readConfig(): Promise<FarmTelemetryConfigState> {\n try {\n const parsed = JSON.parse(\n await readFile(getFarmTelemetryConfigFile(), \"utf8\"),\n ) as Partial<FarmTelemetryConfig>;\n if (parsed.version !== TELEMETRY_SCHEMA_VERSION) {\n return { config: defaultConfig(), stored: false };\n }\n return {\n config: {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: parsed.enabled === true,\n noticeShown: parsed.noticeShown === true,\n anonymousId: isUuid(parsed.anonymousId) ? parsed.anonymousId : undefined,\n },\n stored: true,\n };\n } catch {\n return { config: defaultConfig(), stored: false };\n }\n}\n\nasync function writeConfig(config: FarmTelemetryConfig): Promise<void> {\n const file = getFarmTelemetryConfigFile();\n const directory = path.dirname(file);\n const temporaryFile = `${file}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await writeFile(temporaryFile, `${JSON.stringify(config, null, 2)}\\n`, { mode: 0o600 });\n await rename(temporaryFile, file);\n await chmod(file, 0o600).catch(() => undefined);\n } catch {\n await unlink(temporaryFile).catch(() => undefined);\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nfunction isUuid(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)\n );\n}\n\nfunction isTrue(value: string | undefined): boolean {\n return value !== undefined && [\"1\", \"true\", \"yes\", \"on\"].includes(value.toLowerCase());\n}\n\nfunction isFalse(value: string | undefined): boolean {\n return value !== undefined && [\"0\", \"false\", \"no\", \"off\"].includes(value.toLowerCase());\n}\n\nfunction environmentDecision(): { enabled?: boolean; reason?: string } {\n if (process.env.DO_NOT_TRACK !== undefined && !isFalse(process.env.DO_NOT_TRACK)) {\n return { enabled: false, reason: \"DO_NOT_TRACK is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY_DISABLED)) {\n return { enabled: false, reason: \"FARM_TELEMETRY_DISABLED is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY)) return { enabled: true };\n if (isFalse(process.env.FARM_TELEMETRY)) {\n return { enabled: false, reason: \"FARM_TELEMETRY disables collection\" };\n }\n return {};\n}\n\nfunction isContinuousIntegration(): boolean {\n return (\n isTrue(process.env.CI) ||\n isTrue(process.env.GITHUB_ACTIONS) ||\n isTrue(process.env.BUILDKITE) ||\n isTrue(process.env.CIRCLECI)\n );\n}\n\nfunction isInteractive(): boolean {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n}\n\nfunction getEndpoint(): string {\n const candidate = process.env.FARM_TELEMETRY_ENDPOINT || DEFAULT_TELEMETRY_ENDPOINT;\n try {\n const url = new URL(candidate);\n const isLocal = [\"localhost\", \"127.0.0.1\", \"::1\"].includes(url.hostname);\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && isLocal)) {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n return url.toString();\n } catch {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n}\n\nasync function resolveState(): Promise<{\n config: FarmTelemetryConfig;\n enabled: boolean;\n active: boolean;\n source: FarmTelemetryStatus[\"source\"];\n reason?: string;\n}> {\n const { config, stored } = await readConfig();\n const environment = environmentDecision();\n const enabled = environment.enabled ?? config.enabled;\n const source =\n environment.enabled !== undefined ? \"environment\" : stored ? \"configuration\" : \"default\";\n\n if (!enabled) return { config, enabled, active: false, source, reason: environment.reason };\n if (environment.enabled === true) return { config, enabled, active: true, source };\n if (process.env.NODE_ENV === \"test\") {\n return { config, enabled, active: false, source, reason: \"test environments are skipped\" };\n }\n if (isContinuousIntegration()) {\n return { config, enabled, active: false, source, reason: \"CI environments are skipped\" };\n }\n if (!isInteractive()) {\n return {\n config,\n enabled,\n active: false,\n source,\n reason: \"non-interactive commands are skipped\",\n };\n }\n return { config, enabled, active: true, source };\n}\n\nexport async function getFarmTelemetryStatus(): Promise<FarmTelemetryStatus> {\n const state = await resolveState();\n return {\n enabled: state.enabled,\n active: state.active,\n source: state.source,\n endpoint: getEndpoint(),\n configFile: getFarmTelemetryConfigFile(),\n anonymousId: state.config.anonymousId,\n reason: state.reason,\n };\n}\n\nexport async function setFarmTelemetryEnabled(enabled: boolean): Promise<FarmTelemetryStatus> {\n const { config: current } = await readConfig();\n await writeConfig({\n version: TELEMETRY_SCHEMA_VERSION,\n enabled,\n noticeShown: true,\n anonymousId: enabled ? current.anonymousId || randomUUID() : undefined,\n });\n return getFarmTelemetryStatus();\n}\n\nexport async function showFarmTelemetryNotice(): Promise<void> {\n if (!isInteractive() || isContinuousIntegration() || process.env.NODE_ENV === \"test\") return;\n if (environmentDecision().enabled !== undefined) return;\n const { config } = await readConfig();\n if (config.noticeShown) return;\n process.stderr.write(\n `Farm.js collects anonymous CLI telemetry by default. Run \"farm telemetry disable\" to opt out.\\nLearn more: ${TELEMETRY_NOTICE_URL}\\n`,\n );\n await writeConfig({ ...config, noticeShown: true });\n}\n\nexport function resolveFarmTelemetryCommand(value: string): FarmTelemetryCommand | undefined {\n return (FARM_COMMANDS as readonly string[]).includes(value)\n ? (value as FarmTelemetryCommand)\n : undefined;\n}\n\nexport async function trackFarmCommand(input: FarmCommandTelemetryInput): Promise<void> {\n const deployTarget = allowlisted(input.deployTarget, DEPLOY_TARGETS);\n await track({\n eventType: \"command_invoked\",\n source: \"cli\",\n packageName: \"@farm.js/cli\",\n packageVersion: sanitizeVersion(input.packageVersion),\n command: input.command,\n ...(deployTarget ? { deployTarget } : {}),\n });\n}\n\nexport async function trackFarmProjectCreated(\n input: FarmProjectCreatedTelemetryInput,\n): Promise<void> {\n const template = allowlisted(input.template, FARM_TEMPLATES);\n const renderer = allowlisted(input.renderer, RENDERERS);\n const packageManager = allowlisted(input.packageManager, PACKAGE_MANAGERS);\n await track({\n eventType: \"project_created\",\n source: \"create-app\",\n packageName: \"@farm.js/create-app\",\n packageVersion: sanitizeVersion(input.packageVersion),\n ...(template ? { template } : {}),\n ...(renderer ? { renderer } : {}),\n ...(packageManager ? { packageManager } : {}),\n ...(typeof input.typescript === \"boolean\" ? { typescript: input.typescript } : {}),\n ...(typeof input.installedDependencies === \"boolean\"\n ? { installedDependencies: input.installedDependencies }\n : {}),\n });\n}\n\nasync function track(event: FarmTelemetryEventInput): Promise<void> {\n try {\n const state = await resolveState();\n if (!state.active) return;\n const anonymousId = state.config.anonymousId || randomUUID();\n if (!state.config.anonymousId) {\n await writeConfig({ ...state.config, anonymousId });\n }\n const payload = {\n schemaVersion: TELEMETRY_SCHEMA_VERSION,\n eventId: randomUUID(),\n anonymousId,\n nodeMajor: Number.parseInt(process.versions.node.split(\".\")[0] || \"0\", 10),\n platform: normalizePlatform(process.platform),\n architecture: normalizeArchitecture(process.arch),\n ...event,\n } as FarmTelemetryEvent;\n await send(payload);\n } catch {\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nasync function send(payload: FarmTelemetryEvent): Promise<void> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n timeout.unref?.();\n try {\n await fetch(getEndpoint(), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: controller.signal,\n keepalive: true,\n });\n } catch {\n // Network and endpoint failures are intentionally ignored.\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction sanitizeVersion(value: string): string {\n return /^[0-9A-Za-z.+_-]{1,64}$/.test(value) ? value : \"unknown\";\n}\n\nfunction allowlisted<const T extends readonly string[]>(\n value: string | undefined,\n values: T,\n): T[number] | undefined {\n return value && (values as readonly string[]).includes(value) ? (value as T[number]) : undefined;\n}\n\nfunction normalizePlatform(value: NodeJS.Platform): FarmTelemetryEventBase[\"platform\"] {\n if (value === \"darwin\" || value === \"linux\") return value;\n if (value === \"win32\") return \"windows\";\n return \"other\";\n}\n\nfunction normalizeArchitecture(value: string): FarmTelemetryEventBase[\"architecture\"] {\n return value === \"arm64\" || value === \"x64\" ? value : \"other\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"telemetry.js","names":["path","os","readFile","randomUUID","mkdir","writeFile","rename","chmod","unlink"],"sources":["../src/telemetry.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { chmod, mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst TELEMETRY_SCHEMA_VERSION = 1 as const;\nconst DEFAULT_TELEMETRY_ENDPOINT = \"https://farmjs.dev/api/telemetry/v1/events\";\nconst TELEMETRY_NOTICE_URL = \"https://farmjs.dev/docs/telemetry\";\nconst REQUEST_TIMEOUT_MS = 750;\n\nconst FARM_COMMANDS = [\n \"dev\",\n \"build\",\n \"auth:migrate\",\n \"upgrade\",\n \"generate\",\n \"doctor\",\n \"explain\",\n \"preview\",\n \"migrate\",\n \"cron:list\",\n \"cron:run\",\n \"add:integration\",\n \"deploy\",\n] as const;\n\nconst CREATE_APP_COMMANDS = [\"create\", \"list-templates\"] as const;\n\nconst FARM_TEMPLATES = [\n \"basic\",\n \"react-compiler\",\n \"auth\",\n \"better-auth\",\n \"ai\",\n \"auth0\",\n \"authjs\",\n \"autumn\",\n \"clerk\",\n \"jobs-inngest\",\n \"jobs-trigger\",\n \"polar\",\n \"resend\",\n \"stripe\",\n \"supabase\",\n \"unkey\",\n \"workos\",\n] as const;\n\nconst RENDERERS = [\"react\", \"preact\", \"solid\", \"vue\", \"svelte\"] as const;\nconst PACKAGE_MANAGERS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const;\nconst DEPLOY_TARGETS = [\"vercel\", \"cloudflare\", \"netlify\", \"node\", \"custom\"] as const;\n\nexport type FarmTelemetryCommand = (typeof FARM_COMMANDS)[number];\nexport type FarmCreateAppTelemetryCommand = (typeof CREATE_APP_COMMANDS)[number];\nexport type FarmTelemetryTemplate = (typeof FARM_TEMPLATES)[number];\nexport type FarmTelemetryRenderer = (typeof RENDERERS)[number];\nexport type FarmTelemetryPackageManager = (typeof PACKAGE_MANAGERS)[number];\nexport type FarmTelemetryDeployTarget = (typeof DEPLOY_TARGETS)[number];\n\ninterface FarmTelemetryConfig {\n version: 1;\n enabled: boolean;\n noticeShown: boolean;\n anonymousId?: string;\n}\n\ninterface FarmTelemetryConfigState {\n config: FarmTelemetryConfig;\n stored: boolean;\n}\n\ninterface FarmTelemetryEventBase {\n schemaVersion: typeof TELEMETRY_SCHEMA_VERSION;\n eventId: string;\n anonymousId: string;\n source: \"cli\" | \"create-app\";\n packageName: \"@farm.js/cli\" | \"@farm.js/create-app\";\n packageVersion: string;\n nodeMajor: number;\n platform: \"darwin\" | \"linux\" | \"windows\" | \"other\";\n architecture: \"arm64\" | \"x64\" | \"other\";\n}\n\nexport interface FarmCommandTelemetryInput {\n command: FarmTelemetryCommand;\n packageVersion: string;\n deployTarget?: string;\n}\n\nexport interface FarmCreateAppCommandTelemetryInput {\n command: FarmCreateAppTelemetryCommand;\n packageVersion: string;\n}\n\nexport interface FarmProjectCreatedTelemetryInput {\n packageVersion: string;\n template?: string;\n renderer?: string;\n packageManager?: string;\n typescript?: boolean;\n installedDependencies?: boolean;\n}\n\nexport interface FarmTelemetryStatus {\n enabled: boolean;\n active: boolean;\n source: \"configuration\" | \"environment\" | \"default\";\n endpoint: string;\n configFile: string;\n anonymousId?: string;\n reason?: string;\n}\n\ntype FarmTelemetryEvent =\n | (FarmTelemetryEventBase & {\n eventType: \"command_invoked\";\n source: \"cli\";\n packageName: \"@farm.js/cli\";\n command: FarmTelemetryCommand;\n deployTarget?: FarmTelemetryDeployTarget;\n })\n | (FarmTelemetryEventBase & {\n eventType: \"command_invoked\";\n source: \"create-app\";\n packageName: \"@farm.js/create-app\";\n command: FarmCreateAppTelemetryCommand;\n })\n | (FarmTelemetryEventBase & {\n eventType: \"project_created\";\n source: \"create-app\";\n packageName: \"@farm.js/create-app\";\n template?: FarmTelemetryTemplate;\n renderer?: FarmTelemetryRenderer;\n packageManager?: FarmTelemetryPackageManager;\n typescript?: boolean;\n installedDependencies?: boolean;\n });\n\ntype FarmTelemetryGeneratedFields = Pick<\n FarmTelemetryEventBase,\n \"schemaVersion\" | \"eventId\" | \"anonymousId\" | \"nodeMajor\" | \"platform\" | \"architecture\"\n>;\ntype FarmTelemetryEventInput<T = FarmTelemetryEvent> = T extends FarmTelemetryEvent\n ? Omit<T, keyof FarmTelemetryGeneratedFields>\n : never;\n\nfunction defaultConfig(): FarmTelemetryConfig {\n return {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: true,\n noticeShown: false,\n };\n}\n\nfunction configDirectory(): string {\n if (process.env.FARM_TELEMETRY_CONFIG_DIR) {\n return path.resolve(process.env.FARM_TELEMETRY_CONFIG_DIR);\n }\n if (process.platform === \"win32\") {\n return path.join(\n process.env.APPDATA || path.join(os.homedir(), \"AppData\", \"Roaming\"),\n \"farmjs\",\n );\n }\n if (process.platform === \"darwin\") {\n return path.join(os.homedir(), \"Library\", \"Application Support\", \"farmjs\");\n }\n return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), \".config\"), \"farmjs\");\n}\n\nexport function getFarmTelemetryConfigFile(): string {\n return path.join(configDirectory(), \"telemetry.json\");\n}\n\nasync function readConfig(): Promise<FarmTelemetryConfigState> {\n try {\n const parsed = JSON.parse(\n await readFile(getFarmTelemetryConfigFile(), \"utf8\"),\n ) as Partial<FarmTelemetryConfig>;\n if (parsed.version !== TELEMETRY_SCHEMA_VERSION) {\n return { config: defaultConfig(), stored: false };\n }\n return {\n config: {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: parsed.enabled === true,\n noticeShown: parsed.noticeShown === true,\n anonymousId: isUuid(parsed.anonymousId) ? parsed.anonymousId : undefined,\n },\n stored: true,\n };\n } catch {\n return { config: defaultConfig(), stored: false };\n }\n}\n\nasync function writeConfig(config: FarmTelemetryConfig): Promise<void> {\n const file = getFarmTelemetryConfigFile();\n const directory = path.dirname(file);\n const temporaryFile = `${file}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await writeFile(temporaryFile, `${JSON.stringify(config, null, 2)}\\n`, { mode: 0o600 });\n await rename(temporaryFile, file);\n await chmod(file, 0o600).catch(() => undefined);\n } catch {\n await unlink(temporaryFile).catch(() => undefined);\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nfunction isUuid(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)\n );\n}\n\nfunction isTrue(value: string | undefined): boolean {\n return value !== undefined && [\"1\", \"true\", \"yes\", \"on\"].includes(value.toLowerCase());\n}\n\nfunction isFalse(value: string | undefined): boolean {\n return value !== undefined && [\"0\", \"false\", \"no\", \"off\"].includes(value.toLowerCase());\n}\n\nfunction environmentDecision(): { enabled?: boolean; reason?: string } {\n if (process.env.DO_NOT_TRACK !== undefined && !isFalse(process.env.DO_NOT_TRACK)) {\n return { enabled: false, reason: \"DO_NOT_TRACK is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY_DISABLED)) {\n return { enabled: false, reason: \"FARM_TELEMETRY_DISABLED is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY)) return { enabled: true };\n if (isFalse(process.env.FARM_TELEMETRY)) {\n return { enabled: false, reason: \"FARM_TELEMETRY disables collection\" };\n }\n return {};\n}\n\nfunction isContinuousIntegration(): boolean {\n return (\n isTrue(process.env.CI) ||\n isTrue(process.env.GITHUB_ACTIONS) ||\n isTrue(process.env.BUILDKITE) ||\n isTrue(process.env.CIRCLECI)\n );\n}\n\nfunction isInteractive(): boolean {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n}\n\nfunction getEndpoint(): string {\n const candidate = process.env.FARM_TELEMETRY_ENDPOINT || DEFAULT_TELEMETRY_ENDPOINT;\n try {\n const url = new URL(candidate);\n const isLocal = [\"localhost\", \"127.0.0.1\", \"::1\"].includes(url.hostname);\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && isLocal)) {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n return url.toString();\n } catch {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n}\n\nasync function resolveState(): Promise<{\n config: FarmTelemetryConfig;\n enabled: boolean;\n active: boolean;\n source: FarmTelemetryStatus[\"source\"];\n reason?: string;\n}> {\n const { config, stored } = await readConfig();\n const environment = environmentDecision();\n const enabled = environment.enabled ?? config.enabled;\n const source =\n environment.enabled !== undefined ? \"environment\" : stored ? \"configuration\" : \"default\";\n\n if (!enabled) return { config, enabled, active: false, source, reason: environment.reason };\n if (environment.enabled === true) return { config, enabled, active: true, source };\n if (process.env.NODE_ENV === \"test\") {\n return { config, enabled, active: false, source, reason: \"test environments are skipped\" };\n }\n if (isContinuousIntegration()) {\n return { config, enabled, active: false, source, reason: \"CI environments are skipped\" };\n }\n if (!isInteractive()) {\n return {\n config,\n enabled,\n active: false,\n source,\n reason: \"non-interactive commands are skipped\",\n };\n }\n return { config, enabled, active: true, source };\n}\n\nexport async function getFarmTelemetryStatus(): Promise<FarmTelemetryStatus> {\n const state = await resolveState();\n return {\n enabled: state.enabled,\n active: state.active,\n source: state.source,\n endpoint: getEndpoint(),\n configFile: getFarmTelemetryConfigFile(),\n anonymousId: state.config.anonymousId,\n reason: state.reason,\n };\n}\n\nexport async function setFarmTelemetryEnabled(enabled: boolean): Promise<FarmTelemetryStatus> {\n const { config: current } = await readConfig();\n await writeConfig({\n version: TELEMETRY_SCHEMA_VERSION,\n enabled,\n noticeShown: true,\n anonymousId: enabled ? current.anonymousId || randomUUID() : undefined,\n });\n return getFarmTelemetryStatus();\n}\n\nexport async function showFarmTelemetryNotice(): Promise<void> {\n if (!isInteractive() || isContinuousIntegration() || process.env.NODE_ENV === \"test\") return;\n if (environmentDecision().enabled !== undefined) return;\n const { config } = await readConfig();\n if (config.noticeShown) return;\n process.stderr.write(\n `Farm.js collects anonymous CLI telemetry by default. Run \"farm telemetry disable\" to opt out.\\nLearn more: ${TELEMETRY_NOTICE_URL}\\n`,\n );\n await writeConfig({ ...config, noticeShown: true });\n}\n\nexport function resolveFarmTelemetryCommand(value: string): FarmTelemetryCommand | undefined {\n return (FARM_COMMANDS as readonly string[]).includes(value)\n ? (value as FarmTelemetryCommand)\n : undefined;\n}\n\nexport function resolveFarmCreateAppTelemetryCommand(\n value: string,\n): FarmCreateAppTelemetryCommand | undefined {\n return (CREATE_APP_COMMANDS as readonly string[]).includes(value)\n ? (value as FarmCreateAppTelemetryCommand)\n : undefined;\n}\n\nexport async function trackFarmCommand(input: FarmCommandTelemetryInput): Promise<void> {\n const deployTarget = allowlisted(input.deployTarget, DEPLOY_TARGETS);\n await track({\n eventType: \"command_invoked\",\n source: \"cli\",\n packageName: \"@farm.js/cli\",\n packageVersion: sanitizeVersion(input.packageVersion),\n command: input.command,\n ...(deployTarget ? { deployTarget } : {}),\n });\n}\n\nexport async function trackFarmCreateAppCommand(\n input: FarmCreateAppCommandTelemetryInput,\n): Promise<void> {\n const command = allowlisted(input.command, CREATE_APP_COMMANDS);\n if (!command) return;\n await track({\n eventType: \"command_invoked\",\n source: \"create-app\",\n packageName: \"@farm.js/create-app\",\n packageVersion: sanitizeVersion(input.packageVersion),\n command,\n });\n}\n\nexport async function trackFarmProjectCreated(\n input: FarmProjectCreatedTelemetryInput,\n): Promise<void> {\n const template = allowlisted(input.template, FARM_TEMPLATES);\n const renderer = allowlisted(input.renderer, RENDERERS);\n const packageManager = allowlisted(input.packageManager, PACKAGE_MANAGERS);\n await track({\n eventType: \"project_created\",\n source: \"create-app\",\n packageName: \"@farm.js/create-app\",\n packageVersion: sanitizeVersion(input.packageVersion),\n ...(template ? { template } : {}),\n ...(renderer ? { renderer } : {}),\n ...(packageManager ? { packageManager } : {}),\n ...(typeof input.typescript === \"boolean\" ? { typescript: input.typescript } : {}),\n ...(typeof input.installedDependencies === \"boolean\"\n ? { installedDependencies: input.installedDependencies }\n : {}),\n });\n}\n\nasync function track(event: FarmTelemetryEventInput): Promise<void> {\n try {\n const state = await resolveState();\n if (!state.active) return;\n const anonymousId = state.config.anonymousId || randomUUID();\n if (!state.config.anonymousId) {\n await writeConfig({ ...state.config, anonymousId });\n }\n const payload = {\n schemaVersion: TELEMETRY_SCHEMA_VERSION,\n eventId: randomUUID(),\n anonymousId,\n nodeMajor: Number.parseInt(process.versions.node.split(\".\")[0] || \"0\", 10),\n platform: normalizePlatform(process.platform),\n architecture: normalizeArchitecture(process.arch),\n ...event,\n } as FarmTelemetryEvent;\n await send(payload);\n } catch {\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nasync function send(payload: FarmTelemetryEvent): Promise<void> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n timeout.unref?.();\n try {\n await fetch(getEndpoint(), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: controller.signal,\n keepalive: true,\n });\n } catch {\n // Network and endpoint failures are intentionally ignored.\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction sanitizeVersion(value: string): string {\n return /^[0-9A-Za-z.+_-]{1,64}$/.test(value) ? value : \"unknown\";\n}\n\nfunction allowlisted<const T extends readonly string[]>(\n value: string | undefined,\n values: T,\n): T[number] | undefined {\n return value && (values as readonly string[]).includes(value) ? (value as T[number]) : undefined;\n}\n\nfunction normalizePlatform(value: NodeJS.Platform): FarmTelemetryEventBase[\"platform\"] {\n if (value === \"darwin\" || value === \"linux\") return value;\n if (value === \"win32\") return \"windows\";\n return \"other\";\n}\n\nfunction normalizeArchitecture(value: string): FarmTelemetryEventBase[\"architecture\"] {\n return value === \"arm64\" || value === \"x64\" ? value : \"other\";\n}\n"],"mappings":"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"}
@@ -22,6 +22,7 @@ const FARM_COMMANDS = [
22
22
  "add:integration",
23
23
  "deploy"
24
24
  ];
25
+ const CREATE_APP_COMMANDS = ["create", "list-templates"];
25
26
  const FARM_TEMPLATES = [
26
27
  "basic",
27
28
  "react-compiler",
@@ -254,6 +255,9 @@ async function showFarmTelemetryNotice() {
254
255
  function resolveFarmTelemetryCommand(value) {
255
256
  return FARM_COMMANDS.includes(value) ? value : void 0;
256
257
  }
258
+ function resolveFarmCreateAppTelemetryCommand(value) {
259
+ return CREATE_APP_COMMANDS.includes(value) ? value : void 0;
260
+ }
257
261
  async function trackFarmCommand(input) {
258
262
  const deployTarget = allowlisted(input.deployTarget, DEPLOY_TARGETS);
259
263
  await track({
@@ -265,6 +269,17 @@ async function trackFarmCommand(input) {
265
269
  ...deployTarget ? { deployTarget } : {}
266
270
  });
267
271
  }
272
+ async function trackFarmCreateAppCommand(input) {
273
+ const command = allowlisted(input.command, CREATE_APP_COMMANDS);
274
+ if (!command) return;
275
+ await track({
276
+ eventType: "command_invoked",
277
+ source: "create-app",
278
+ packageName: "@farm.js/create-app",
279
+ packageVersion: sanitizeVersion(input.packageVersion),
280
+ command
281
+ });
282
+ }
268
283
  async function trackFarmProjectCreated(input) {
269
284
  const template = allowlisted(input.template, FARM_TEMPLATES);
270
285
  const renderer = allowlisted(input.renderer, RENDERERS);
@@ -332,6 +347,6 @@ function normalizeArchitecture(value) {
332
347
  return value === "arm64" || value === "x64" ? value : "other";
333
348
  }
334
349
  //#endregion
335
- export { getFarmTelemetryConfigFile, getFarmTelemetryStatus, resolveFarmTelemetryCommand, setFarmTelemetryEnabled, showFarmTelemetryNotice, trackFarmCommand, trackFarmProjectCreated };
350
+ export { getFarmTelemetryConfigFile, getFarmTelemetryStatus, resolveFarmCreateAppTelemetryCommand, resolveFarmTelemetryCommand, setFarmTelemetryEnabled, showFarmTelemetryNotice, trackFarmCommand, trackFarmCreateAppCommand, trackFarmProjectCreated };
336
351
 
337
352
  //# sourceMappingURL=telemetry.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.mjs","names":[],"sources":["../src/telemetry.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { chmod, mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst TELEMETRY_SCHEMA_VERSION = 1 as const;\nconst DEFAULT_TELEMETRY_ENDPOINT = \"https://farmjs.dev/api/telemetry/v1/events\";\nconst TELEMETRY_NOTICE_URL = \"https://farmjs.dev/docs/telemetry\";\nconst REQUEST_TIMEOUT_MS = 750;\n\nconst FARM_COMMANDS = [\n \"dev\",\n \"build\",\n \"auth:migrate\",\n \"upgrade\",\n \"generate\",\n \"doctor\",\n \"explain\",\n \"preview\",\n \"migrate\",\n \"cron:list\",\n \"cron:run\",\n \"add:integration\",\n \"deploy\",\n] as const;\n\nconst FARM_TEMPLATES = [\n \"basic\",\n \"react-compiler\",\n \"auth\",\n \"better-auth\",\n \"ai\",\n \"auth0\",\n \"authjs\",\n \"autumn\",\n \"clerk\",\n \"jobs-inngest\",\n \"jobs-trigger\",\n \"polar\",\n \"resend\",\n \"stripe\",\n \"supabase\",\n \"unkey\",\n \"workos\",\n] as const;\n\nconst RENDERERS = [\"react\", \"preact\", \"solid\", \"vue\", \"svelte\"] as const;\nconst PACKAGE_MANAGERS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const;\nconst DEPLOY_TARGETS = [\"vercel\", \"cloudflare\", \"netlify\", \"node\", \"custom\"] as const;\n\nexport type FarmTelemetryCommand = (typeof FARM_COMMANDS)[number];\nexport type FarmTelemetryTemplate = (typeof FARM_TEMPLATES)[number];\nexport type FarmTelemetryRenderer = (typeof RENDERERS)[number];\nexport type FarmTelemetryPackageManager = (typeof PACKAGE_MANAGERS)[number];\nexport type FarmTelemetryDeployTarget = (typeof DEPLOY_TARGETS)[number];\n\ninterface FarmTelemetryConfig {\n version: 1;\n enabled: boolean;\n noticeShown: boolean;\n anonymousId?: string;\n}\n\ninterface FarmTelemetryConfigState {\n config: FarmTelemetryConfig;\n stored: boolean;\n}\n\ninterface FarmTelemetryEventBase {\n schemaVersion: typeof TELEMETRY_SCHEMA_VERSION;\n eventId: string;\n anonymousId: string;\n source: \"cli\" | \"create-app\";\n packageName: \"@farm.js/cli\" | \"@farm.js/create-app\";\n packageVersion: string;\n nodeMajor: number;\n platform: \"darwin\" | \"linux\" | \"windows\" | \"other\";\n architecture: \"arm64\" | \"x64\" | \"other\";\n}\n\nexport interface FarmCommandTelemetryInput {\n command: FarmTelemetryCommand;\n packageVersion: string;\n deployTarget?: string;\n}\n\nexport interface FarmProjectCreatedTelemetryInput {\n packageVersion: string;\n template?: string;\n renderer?: string;\n packageManager?: string;\n typescript?: boolean;\n installedDependencies?: boolean;\n}\n\nexport interface FarmTelemetryStatus {\n enabled: boolean;\n active: boolean;\n source: \"configuration\" | \"environment\" | \"default\";\n endpoint: string;\n configFile: string;\n anonymousId?: string;\n reason?: string;\n}\n\ntype FarmTelemetryEvent =\n | (FarmTelemetryEventBase & {\n eventType: \"command_invoked\";\n command: FarmTelemetryCommand;\n deployTarget?: FarmTelemetryDeployTarget;\n })\n | (FarmTelemetryEventBase & {\n eventType: \"project_created\";\n template?: FarmTelemetryTemplate;\n renderer?: FarmTelemetryRenderer;\n packageManager?: FarmTelemetryPackageManager;\n typescript?: boolean;\n installedDependencies?: boolean;\n });\n\ntype FarmTelemetryGeneratedFields = Pick<\n FarmTelemetryEventBase,\n \"schemaVersion\" | \"eventId\" | \"anonymousId\" | \"nodeMajor\" | \"platform\" | \"architecture\"\n>;\ntype FarmTelemetryEventInput<T = FarmTelemetryEvent> = T extends FarmTelemetryEvent\n ? Omit<T, keyof FarmTelemetryGeneratedFields>\n : never;\n\nfunction defaultConfig(): FarmTelemetryConfig {\n return {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: true,\n noticeShown: false,\n };\n}\n\nfunction configDirectory(): string {\n if (process.env.FARM_TELEMETRY_CONFIG_DIR) {\n return path.resolve(process.env.FARM_TELEMETRY_CONFIG_DIR);\n }\n if (process.platform === \"win32\") {\n return path.join(\n process.env.APPDATA || path.join(os.homedir(), \"AppData\", \"Roaming\"),\n \"farmjs\",\n );\n }\n if (process.platform === \"darwin\") {\n return path.join(os.homedir(), \"Library\", \"Application Support\", \"farmjs\");\n }\n return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), \".config\"), \"farmjs\");\n}\n\nexport function getFarmTelemetryConfigFile(): string {\n return path.join(configDirectory(), \"telemetry.json\");\n}\n\nasync function readConfig(): Promise<FarmTelemetryConfigState> {\n try {\n const parsed = JSON.parse(\n await readFile(getFarmTelemetryConfigFile(), \"utf8\"),\n ) as Partial<FarmTelemetryConfig>;\n if (parsed.version !== TELEMETRY_SCHEMA_VERSION) {\n return { config: defaultConfig(), stored: false };\n }\n return {\n config: {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: parsed.enabled === true,\n noticeShown: parsed.noticeShown === true,\n anonymousId: isUuid(parsed.anonymousId) ? parsed.anonymousId : undefined,\n },\n stored: true,\n };\n } catch {\n return { config: defaultConfig(), stored: false };\n }\n}\n\nasync function writeConfig(config: FarmTelemetryConfig): Promise<void> {\n const file = getFarmTelemetryConfigFile();\n const directory = path.dirname(file);\n const temporaryFile = `${file}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await writeFile(temporaryFile, `${JSON.stringify(config, null, 2)}\\n`, { mode: 0o600 });\n await rename(temporaryFile, file);\n await chmod(file, 0o600).catch(() => undefined);\n } catch {\n await unlink(temporaryFile).catch(() => undefined);\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nfunction isUuid(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)\n );\n}\n\nfunction isTrue(value: string | undefined): boolean {\n return value !== undefined && [\"1\", \"true\", \"yes\", \"on\"].includes(value.toLowerCase());\n}\n\nfunction isFalse(value: string | undefined): boolean {\n return value !== undefined && [\"0\", \"false\", \"no\", \"off\"].includes(value.toLowerCase());\n}\n\nfunction environmentDecision(): { enabled?: boolean; reason?: string } {\n if (process.env.DO_NOT_TRACK !== undefined && !isFalse(process.env.DO_NOT_TRACK)) {\n return { enabled: false, reason: \"DO_NOT_TRACK is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY_DISABLED)) {\n return { enabled: false, reason: \"FARM_TELEMETRY_DISABLED is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY)) return { enabled: true };\n if (isFalse(process.env.FARM_TELEMETRY)) {\n return { enabled: false, reason: \"FARM_TELEMETRY disables collection\" };\n }\n return {};\n}\n\nfunction isContinuousIntegration(): boolean {\n return (\n isTrue(process.env.CI) ||\n isTrue(process.env.GITHUB_ACTIONS) ||\n isTrue(process.env.BUILDKITE) ||\n isTrue(process.env.CIRCLECI)\n );\n}\n\nfunction isInteractive(): boolean {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n}\n\nfunction getEndpoint(): string {\n const candidate = process.env.FARM_TELEMETRY_ENDPOINT || DEFAULT_TELEMETRY_ENDPOINT;\n try {\n const url = new URL(candidate);\n const isLocal = [\"localhost\", \"127.0.0.1\", \"::1\"].includes(url.hostname);\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && isLocal)) {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n return url.toString();\n } catch {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n}\n\nasync function resolveState(): Promise<{\n config: FarmTelemetryConfig;\n enabled: boolean;\n active: boolean;\n source: FarmTelemetryStatus[\"source\"];\n reason?: string;\n}> {\n const { config, stored } = await readConfig();\n const environment = environmentDecision();\n const enabled = environment.enabled ?? config.enabled;\n const source =\n environment.enabled !== undefined ? \"environment\" : stored ? \"configuration\" : \"default\";\n\n if (!enabled) return { config, enabled, active: false, source, reason: environment.reason };\n if (environment.enabled === true) return { config, enabled, active: true, source };\n if (process.env.NODE_ENV === \"test\") {\n return { config, enabled, active: false, source, reason: \"test environments are skipped\" };\n }\n if (isContinuousIntegration()) {\n return { config, enabled, active: false, source, reason: \"CI environments are skipped\" };\n }\n if (!isInteractive()) {\n return {\n config,\n enabled,\n active: false,\n source,\n reason: \"non-interactive commands are skipped\",\n };\n }\n return { config, enabled, active: true, source };\n}\n\nexport async function getFarmTelemetryStatus(): Promise<FarmTelemetryStatus> {\n const state = await resolveState();\n return {\n enabled: state.enabled,\n active: state.active,\n source: state.source,\n endpoint: getEndpoint(),\n configFile: getFarmTelemetryConfigFile(),\n anonymousId: state.config.anonymousId,\n reason: state.reason,\n };\n}\n\nexport async function setFarmTelemetryEnabled(enabled: boolean): Promise<FarmTelemetryStatus> {\n const { config: current } = await readConfig();\n await writeConfig({\n version: TELEMETRY_SCHEMA_VERSION,\n enabled,\n noticeShown: true,\n anonymousId: enabled ? current.anonymousId || randomUUID() : undefined,\n });\n return getFarmTelemetryStatus();\n}\n\nexport async function showFarmTelemetryNotice(): Promise<void> {\n if (!isInteractive() || isContinuousIntegration() || process.env.NODE_ENV === \"test\") return;\n if (environmentDecision().enabled !== undefined) return;\n const { config } = await readConfig();\n if (config.noticeShown) return;\n process.stderr.write(\n `Farm.js collects anonymous CLI telemetry by default. Run \"farm telemetry disable\" to opt out.\\nLearn more: ${TELEMETRY_NOTICE_URL}\\n`,\n );\n await writeConfig({ ...config, noticeShown: true });\n}\n\nexport function resolveFarmTelemetryCommand(value: string): FarmTelemetryCommand | undefined {\n return (FARM_COMMANDS as readonly string[]).includes(value)\n ? (value as FarmTelemetryCommand)\n : undefined;\n}\n\nexport async function trackFarmCommand(input: FarmCommandTelemetryInput): Promise<void> {\n const deployTarget = allowlisted(input.deployTarget, DEPLOY_TARGETS);\n await track({\n eventType: \"command_invoked\",\n source: \"cli\",\n packageName: \"@farm.js/cli\",\n packageVersion: sanitizeVersion(input.packageVersion),\n command: input.command,\n ...(deployTarget ? { deployTarget } : {}),\n });\n}\n\nexport async function trackFarmProjectCreated(\n input: FarmProjectCreatedTelemetryInput,\n): Promise<void> {\n const template = allowlisted(input.template, FARM_TEMPLATES);\n const renderer = allowlisted(input.renderer, RENDERERS);\n const packageManager = allowlisted(input.packageManager, PACKAGE_MANAGERS);\n await track({\n eventType: \"project_created\",\n source: \"create-app\",\n packageName: \"@farm.js/create-app\",\n packageVersion: sanitizeVersion(input.packageVersion),\n ...(template ? { template } : {}),\n ...(renderer ? { renderer } : {}),\n ...(packageManager ? { packageManager } : {}),\n ...(typeof input.typescript === \"boolean\" ? { typescript: input.typescript } : {}),\n ...(typeof input.installedDependencies === \"boolean\"\n ? { installedDependencies: input.installedDependencies }\n : {}),\n });\n}\n\nasync function track(event: FarmTelemetryEventInput): Promise<void> {\n try {\n const state = await resolveState();\n if (!state.active) return;\n const anonymousId = state.config.anonymousId || randomUUID();\n if (!state.config.anonymousId) {\n await writeConfig({ ...state.config, anonymousId });\n }\n const payload = {\n schemaVersion: TELEMETRY_SCHEMA_VERSION,\n eventId: randomUUID(),\n anonymousId,\n nodeMajor: Number.parseInt(process.versions.node.split(\".\")[0] || \"0\", 10),\n platform: normalizePlatform(process.platform),\n architecture: normalizeArchitecture(process.arch),\n ...event,\n } as FarmTelemetryEvent;\n await send(payload);\n } catch {\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nasync function send(payload: FarmTelemetryEvent): Promise<void> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n timeout.unref?.();\n try {\n await fetch(getEndpoint(), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: controller.signal,\n keepalive: true,\n });\n } catch {\n // Network and endpoint failures are intentionally ignored.\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction sanitizeVersion(value: string): string {\n return /^[0-9A-Za-z.+_-]{1,64}$/.test(value) ? value : \"unknown\";\n}\n\nfunction allowlisted<const T extends readonly string[]>(\n value: string | undefined,\n values: T,\n): T[number] | undefined {\n return value && (values as readonly string[]).includes(value) ? (value as T[number]) : undefined;\n}\n\nfunction normalizePlatform(value: NodeJS.Platform): FarmTelemetryEventBase[\"platform\"] {\n if (value === \"darwin\" || value === \"linux\") return value;\n if (value === \"win32\") return \"windows\";\n return \"other\";\n}\n\nfunction normalizeArchitecture(value: string): FarmTelemetryEventBase[\"architecture\"] {\n return value === \"arm64\" || value === \"x64\" ? value : \"other\";\n}\n"],"mappings":";;;;;AAKA,MAAM,2BAA2B;AACjC,MAAM,6BAA6B;AACnC,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAE3B,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,YAAY;CAAC;CAAS;CAAU;CAAS;CAAO;AAAQ;AAC9D,MAAM,mBAAmB;CAAC;CAAO;CAAQ;CAAQ;AAAK;AACtD,MAAM,iBAAiB;CAAC;CAAU;CAAc;CAAW;CAAQ;AAAQ;AAgF3E,SAAS,gBAAqC;CAC5C,OAAO;EACL,SAAS;EACT,SAAS;EACT,aAAa;CACf;AACF;AAEA,SAAS,kBAA0B;CACjC,IAAI,QAAQ,IAAI,2BACd,OAAO,KAAK,QAAQ,QAAQ,IAAI,yBAAyB;CAE3D,IAAI,QAAQ,aAAa,SACvB,OAAO,KAAK,KACV,QAAQ,IAAI,WAAW,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,SAAS,GACnE,QACF;CAEF,IAAI,QAAQ,aAAa,UACvB,OAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,uBAAuB,QAAQ;CAE3E,OAAO,KAAK,KAAK,QAAQ,IAAI,mBAAmB,KAAK,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ;AAC9F;AAEA,SAAgB,6BAAqC;CACnD,OAAO,KAAK,KAAK,gBAAgB,GAAG,gBAAgB;AACtD;AAEA,eAAe,aAAgD;CAC7D,IAAI;EACF,MAAM,SAAS,KAAK,MAClB,MAAM,SAAS,2BAA2B,GAAG,MAAM,CACrD;EACA,IAAI,OAAO,YAAY,0BACrB,OAAO;GAAE,QAAQ,cAAc;GAAG,QAAQ;EAAM;EAElD,OAAO;GACL,QAAQ;IACN,SAAS;IACT,SAAS,OAAO,YAAY;IAC5B,aAAa,OAAO,gBAAgB;IACpC,aAAa,OAAO,OAAO,WAAW,IAAI,OAAO,cAAc,KAAA;GACjE;GACA,QAAQ;EACV;CACF,QAAQ;EACN,OAAO;GAAE,QAAQ,cAAc;GAAG,QAAQ;EAAM;CAClD;AACF;AAEA,eAAe,YAAY,QAA4C;CACrE,MAAM,OAAO,2BAA2B;CACxC,MAAM,YAAY,KAAK,QAAQ,IAAI;CACnC,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,IAAI,GAAG,WAAW,EAAE;CAC7D,IAAI;EACF,MAAM,MAAM,WAAW;GAAE,WAAW;GAAM,MAAM;EAAM,CAAC;EACvD,MAAM,UAAU,eAAe,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,IAAM,CAAC;EACtF,MAAM,OAAO,eAAe,IAAI;EAChC,MAAM,MAAM,MAAM,GAAK,CAAC,CAAC,YAAY,KAAA,CAAS;CAChD,QAAQ;EACN,MAAM,OAAO,aAAa,CAAC,CAAC,YAAY,KAAA,CAAS;CAEnD;AACF;AAEA,SAAS,OAAO,OAAiC;CAC/C,OACE,OAAO,UAAU,YACjB,6EAA6E,KAAK,KAAK;AAE3F;AAEA,SAAS,OAAO,OAAoC;CAClD,OAAO,UAAU,KAAA,KAAa;EAAC;EAAK;EAAQ;EAAO;CAAI,CAAC,CAAC,SAAS,MAAM,YAAY,CAAC;AACvF;AAEA,SAAS,QAAQ,OAAoC;CACnD,OAAO,UAAU,KAAA,KAAa;EAAC;EAAK;EAAS;EAAM;CAAK,CAAC,CAAC,SAAS,MAAM,YAAY,CAAC;AACxF;AAEA,SAAS,sBAA8D;CACrE,IAAI,QAAQ,IAAI,iBAAiB,KAAA,KAAa,CAAC,QAAQ,QAAQ,IAAI,YAAY,GAC7E,OAAO;EAAE,SAAS;EAAO,QAAQ;CAAsB;CAEzD,IAAI,OAAO,QAAQ,IAAI,uBAAuB,GAC5C,OAAO;EAAE,SAAS;EAAO,QAAQ;CAAiC;CAEpE,IAAI,OAAO,QAAQ,IAAI,cAAc,GAAG,OAAO,EAAE,SAAS,KAAK;CAC/D,IAAI,QAAQ,QAAQ,IAAI,cAAc,GACpC,OAAO;EAAE,SAAS;EAAO,QAAQ;CAAqC;CAExE,OAAO,CAAC;AACV;AAEA,SAAS,0BAAmC;CAC1C,OACE,OAAO,QAAQ,IAAI,EAAE,KACrB,OAAO,QAAQ,IAAI,cAAc,KACjC,OAAO,QAAQ,IAAI,SAAS,KAC5B,OAAO,QAAQ,IAAI,QAAQ;AAE/B;AAEA,SAAS,gBAAyB;CAChC,OAAO,QAAQ,MAAM,UAAU,QAAQ,QAAQ,OAAO,UAAU;AAClE;AAEA,SAAS,cAAsB;CAC7B,MAAM,YAAY,QAAQ,IAAI,2BAA2B;CACzD,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,SAAS;EAC7B,MAAM,UAAU;GAAC;GAAa;GAAa;EAAK,CAAC,CAAC,SAAS,IAAI,QAAQ;EACvE,IAAI,IAAI,aAAa,YAAY,EAAE,IAAI,aAAa,WAAW,UAC7D,OAAO;EAET,OAAO,IAAI,SAAS;CACtB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAe,eAMZ;CACD,MAAM,EAAE,QAAQ,WAAW,MAAM,WAAW;CAC5C,MAAM,cAAc,oBAAoB;CACxC,MAAM,UAAU,YAAY,WAAW,OAAO;CAC9C,MAAM,SACJ,YAAY,YAAY,KAAA,IAAY,gBAAgB,SAAS,kBAAkB;CAEjF,IAAI,CAAC,SAAS,OAAO;EAAE;EAAQ;EAAS,QAAQ;EAAO;EAAQ,QAAQ,YAAY;CAAO;CAC1F,IAAI,YAAY,YAAY,MAAM,OAAO;EAAE;EAAQ;EAAS,QAAQ;EAAM;CAAO;CACjF,IAAI,QAAQ,IAAI,aAAa,QAC3B,OAAO;EAAE;EAAQ;EAAS,QAAQ;EAAO;EAAQ,QAAQ;CAAgC;CAE3F,IAAI,wBAAwB,GAC1B,OAAO;EAAE;EAAQ;EAAS,QAAQ;EAAO;EAAQ,QAAQ;CAA8B;CAEzF,IAAI,CAAC,cAAc,GACjB,OAAO;EACL;EACA;EACA,QAAQ;EACR;EACA,QAAQ;CACV;CAEF,OAAO;EAAE;EAAQ;EAAS,QAAQ;EAAM;CAAO;AACjD;AAEA,eAAsB,yBAAuD;CAC3E,MAAM,QAAQ,MAAM,aAAa;CACjC,OAAO;EACL,SAAS,MAAM;EACf,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,UAAU,YAAY;EACtB,YAAY,2BAA2B;EACvC,aAAa,MAAM,OAAO;EAC1B,QAAQ,MAAM;CAChB;AACF;AAEA,eAAsB,wBAAwB,SAAgD;CAC5F,MAAM,EAAE,QAAQ,YAAY,MAAM,WAAW;CAC7C,MAAM,YAAY;EAChB,SAAS;EACT;EACA,aAAa;EACb,aAAa,UAAU,QAAQ,eAAe,WAAW,IAAI,KAAA;CAC/D,CAAC;CACD,OAAO,uBAAuB;AAChC;AAEA,eAAsB,0BAAyC;CAC7D,IAAI,CAAC,cAAc,KAAK,wBAAwB,KAAK,QAAQ,IAAI,aAAa,QAAQ;CACtF,IAAI,oBAAoB,CAAC,CAAC,YAAY,KAAA,GAAW;CACjD,MAAM,EAAE,WAAW,MAAM,WAAW;CACpC,IAAI,OAAO,aAAa;CACxB,QAAQ,OAAO,MACb,8GAA8G,qBAAqB,GACrI;CACA,MAAM,YAAY;EAAE,GAAG;EAAQ,aAAa;CAAK,CAAC;AACpD;AAEA,SAAgB,4BAA4B,OAAiD;CAC3F,OAAQ,cAAoC,SAAS,KAAK,IACrD,QACD,KAAA;AACN;AAEA,eAAsB,iBAAiB,OAAiD;CACtF,MAAM,eAAe,YAAY,MAAM,cAAc,cAAc;CACnE,MAAM,MAAM;EACV,WAAW;EACX,QAAQ;EACR,aAAa;EACb,gBAAgB,gBAAgB,MAAM,cAAc;EACpD,SAAS,MAAM;EACf,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;CACzC,CAAC;AACH;AAEA,eAAsB,wBACpB,OACe;CACf,MAAM,WAAW,YAAY,MAAM,UAAU,cAAc;CAC3D,MAAM,WAAW,YAAY,MAAM,UAAU,SAAS;CACtD,MAAM,iBAAiB,YAAY,MAAM,gBAAgB,gBAAgB;CACzE,MAAM,MAAM;EACV,WAAW;EACX,QAAQ;EACR,aAAa;EACb,gBAAgB,gBAAgB,MAAM,cAAc;EACpD,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EAC/B,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EAC/B,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;EAC3C,GAAI,OAAO,MAAM,eAAe,YAAY,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;EAChF,GAAI,OAAO,MAAM,0BAA0B,YACvC,EAAE,uBAAuB,MAAM,sBAAsB,IACrD,CAAC;CACP,CAAC;AACH;AAEA,eAAe,MAAM,OAA+C;CAClE,IAAI;EACF,MAAM,QAAQ,MAAM,aAAa;EACjC,IAAI,CAAC,MAAM,QAAQ;EACnB,MAAM,cAAc,MAAM,OAAO,eAAe,WAAW;EAC3D,IAAI,CAAC,MAAM,OAAO,aAChB,MAAM,YAAY;GAAE,GAAG,MAAM;GAAQ;EAAY,CAAC;EAWpD,MAAM,KAAK;GART,eAAe;GACf,SAAS,WAAW;GACpB;GACA,WAAW,OAAO,SAAS,QAAQ,SAAS,KAAK,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,EAAE;GACzE,UAAU,kBAAkB,QAAQ,QAAQ;GAC5C,cAAc,sBAAsB,QAAQ,IAAI;GAChD,GAAG;EAEY,CAAC;CACpB,QAAQ,CAER;AACF;AAEA,eAAe,KAAK,SAA4C;CAC9D,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,UAAU,iBAAiB,WAAW,MAAM,GAAG,kBAAkB;CACvE,QAAQ,QAAQ;CAChB,IAAI;EACF,MAAM,MAAM,YAAY,GAAG;GACzB,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,MAAM,KAAK,UAAU,OAAO;GAC5B,QAAQ,WAAW;GACnB,WAAW;EACb,CAAC;CACH,QAAQ,CAER,UAAU;EACR,aAAa,OAAO;CACtB;AACF;AAEA,SAAS,gBAAgB,OAAuB;CAC9C,OAAO,0BAA0B,KAAK,KAAK,IAAI,QAAQ;AACzD;AAEA,SAAS,YACP,OACA,QACuB;CACvB,OAAO,SAAU,OAA6B,SAAS,KAAK,IAAK,QAAsB,KAAA;AACzF;AAEA,SAAS,kBAAkB,OAA4D;CACrF,IAAI,UAAU,YAAY,UAAU,SAAS,OAAO;CACpD,IAAI,UAAU,SAAS,OAAO;CAC9B,OAAO;AACT;AAEA,SAAS,sBAAsB,OAAuD;CACpF,OAAO,UAAU,WAAW,UAAU,QAAQ,QAAQ;AACxD"}
1
+ {"version":3,"file":"telemetry.mjs","names":[],"sources":["../src/telemetry.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { chmod, mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst TELEMETRY_SCHEMA_VERSION = 1 as const;\nconst DEFAULT_TELEMETRY_ENDPOINT = \"https://farmjs.dev/api/telemetry/v1/events\";\nconst TELEMETRY_NOTICE_URL = \"https://farmjs.dev/docs/telemetry\";\nconst REQUEST_TIMEOUT_MS = 750;\n\nconst FARM_COMMANDS = [\n \"dev\",\n \"build\",\n \"auth:migrate\",\n \"upgrade\",\n \"generate\",\n \"doctor\",\n \"explain\",\n \"preview\",\n \"migrate\",\n \"cron:list\",\n \"cron:run\",\n \"add:integration\",\n \"deploy\",\n] as const;\n\nconst CREATE_APP_COMMANDS = [\"create\", \"list-templates\"] as const;\n\nconst FARM_TEMPLATES = [\n \"basic\",\n \"react-compiler\",\n \"auth\",\n \"better-auth\",\n \"ai\",\n \"auth0\",\n \"authjs\",\n \"autumn\",\n \"clerk\",\n \"jobs-inngest\",\n \"jobs-trigger\",\n \"polar\",\n \"resend\",\n \"stripe\",\n \"supabase\",\n \"unkey\",\n \"workos\",\n] as const;\n\nconst RENDERERS = [\"react\", \"preact\", \"solid\", \"vue\", \"svelte\"] as const;\nconst PACKAGE_MANAGERS = [\"npm\", \"pnpm\", \"yarn\", \"bun\"] as const;\nconst DEPLOY_TARGETS = [\"vercel\", \"cloudflare\", \"netlify\", \"node\", \"custom\"] as const;\n\nexport type FarmTelemetryCommand = (typeof FARM_COMMANDS)[number];\nexport type FarmCreateAppTelemetryCommand = (typeof CREATE_APP_COMMANDS)[number];\nexport type FarmTelemetryTemplate = (typeof FARM_TEMPLATES)[number];\nexport type FarmTelemetryRenderer = (typeof RENDERERS)[number];\nexport type FarmTelemetryPackageManager = (typeof PACKAGE_MANAGERS)[number];\nexport type FarmTelemetryDeployTarget = (typeof DEPLOY_TARGETS)[number];\n\ninterface FarmTelemetryConfig {\n version: 1;\n enabled: boolean;\n noticeShown: boolean;\n anonymousId?: string;\n}\n\ninterface FarmTelemetryConfigState {\n config: FarmTelemetryConfig;\n stored: boolean;\n}\n\ninterface FarmTelemetryEventBase {\n schemaVersion: typeof TELEMETRY_SCHEMA_VERSION;\n eventId: string;\n anonymousId: string;\n source: \"cli\" | \"create-app\";\n packageName: \"@farm.js/cli\" | \"@farm.js/create-app\";\n packageVersion: string;\n nodeMajor: number;\n platform: \"darwin\" | \"linux\" | \"windows\" | \"other\";\n architecture: \"arm64\" | \"x64\" | \"other\";\n}\n\nexport interface FarmCommandTelemetryInput {\n command: FarmTelemetryCommand;\n packageVersion: string;\n deployTarget?: string;\n}\n\nexport interface FarmCreateAppCommandTelemetryInput {\n command: FarmCreateAppTelemetryCommand;\n packageVersion: string;\n}\n\nexport interface FarmProjectCreatedTelemetryInput {\n packageVersion: string;\n template?: string;\n renderer?: string;\n packageManager?: string;\n typescript?: boolean;\n installedDependencies?: boolean;\n}\n\nexport interface FarmTelemetryStatus {\n enabled: boolean;\n active: boolean;\n source: \"configuration\" | \"environment\" | \"default\";\n endpoint: string;\n configFile: string;\n anonymousId?: string;\n reason?: string;\n}\n\ntype FarmTelemetryEvent =\n | (FarmTelemetryEventBase & {\n eventType: \"command_invoked\";\n source: \"cli\";\n packageName: \"@farm.js/cli\";\n command: FarmTelemetryCommand;\n deployTarget?: FarmTelemetryDeployTarget;\n })\n | (FarmTelemetryEventBase & {\n eventType: \"command_invoked\";\n source: \"create-app\";\n packageName: \"@farm.js/create-app\";\n command: FarmCreateAppTelemetryCommand;\n })\n | (FarmTelemetryEventBase & {\n eventType: \"project_created\";\n source: \"create-app\";\n packageName: \"@farm.js/create-app\";\n template?: FarmTelemetryTemplate;\n renderer?: FarmTelemetryRenderer;\n packageManager?: FarmTelemetryPackageManager;\n typescript?: boolean;\n installedDependencies?: boolean;\n });\n\ntype FarmTelemetryGeneratedFields = Pick<\n FarmTelemetryEventBase,\n \"schemaVersion\" | \"eventId\" | \"anonymousId\" | \"nodeMajor\" | \"platform\" | \"architecture\"\n>;\ntype FarmTelemetryEventInput<T = FarmTelemetryEvent> = T extends FarmTelemetryEvent\n ? Omit<T, keyof FarmTelemetryGeneratedFields>\n : never;\n\nfunction defaultConfig(): FarmTelemetryConfig {\n return {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: true,\n noticeShown: false,\n };\n}\n\nfunction configDirectory(): string {\n if (process.env.FARM_TELEMETRY_CONFIG_DIR) {\n return path.resolve(process.env.FARM_TELEMETRY_CONFIG_DIR);\n }\n if (process.platform === \"win32\") {\n return path.join(\n process.env.APPDATA || path.join(os.homedir(), \"AppData\", \"Roaming\"),\n \"farmjs\",\n );\n }\n if (process.platform === \"darwin\") {\n return path.join(os.homedir(), \"Library\", \"Application Support\", \"farmjs\");\n }\n return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), \".config\"), \"farmjs\");\n}\n\nexport function getFarmTelemetryConfigFile(): string {\n return path.join(configDirectory(), \"telemetry.json\");\n}\n\nasync function readConfig(): Promise<FarmTelemetryConfigState> {\n try {\n const parsed = JSON.parse(\n await readFile(getFarmTelemetryConfigFile(), \"utf8\"),\n ) as Partial<FarmTelemetryConfig>;\n if (parsed.version !== TELEMETRY_SCHEMA_VERSION) {\n return { config: defaultConfig(), stored: false };\n }\n return {\n config: {\n version: TELEMETRY_SCHEMA_VERSION,\n enabled: parsed.enabled === true,\n noticeShown: parsed.noticeShown === true,\n anonymousId: isUuid(parsed.anonymousId) ? parsed.anonymousId : undefined,\n },\n stored: true,\n };\n } catch {\n return { config: defaultConfig(), stored: false };\n }\n}\n\nasync function writeConfig(config: FarmTelemetryConfig): Promise<void> {\n const file = getFarmTelemetryConfigFile();\n const directory = path.dirname(file);\n const temporaryFile = `${file}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await writeFile(temporaryFile, `${JSON.stringify(config, null, 2)}\\n`, { mode: 0o600 });\n await rename(temporaryFile, file);\n await chmod(file, 0o600).catch(() => undefined);\n } catch {\n await unlink(temporaryFile).catch(() => undefined);\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nfunction isUuid(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)\n );\n}\n\nfunction isTrue(value: string | undefined): boolean {\n return value !== undefined && [\"1\", \"true\", \"yes\", \"on\"].includes(value.toLowerCase());\n}\n\nfunction isFalse(value: string | undefined): boolean {\n return value !== undefined && [\"0\", \"false\", \"no\", \"off\"].includes(value.toLowerCase());\n}\n\nfunction environmentDecision(): { enabled?: boolean; reason?: string } {\n if (process.env.DO_NOT_TRACK !== undefined && !isFalse(process.env.DO_NOT_TRACK)) {\n return { enabled: false, reason: \"DO_NOT_TRACK is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY_DISABLED)) {\n return { enabled: false, reason: \"FARM_TELEMETRY_DISABLED is set\" };\n }\n if (isTrue(process.env.FARM_TELEMETRY)) return { enabled: true };\n if (isFalse(process.env.FARM_TELEMETRY)) {\n return { enabled: false, reason: \"FARM_TELEMETRY disables collection\" };\n }\n return {};\n}\n\nfunction isContinuousIntegration(): boolean {\n return (\n isTrue(process.env.CI) ||\n isTrue(process.env.GITHUB_ACTIONS) ||\n isTrue(process.env.BUILDKITE) ||\n isTrue(process.env.CIRCLECI)\n );\n}\n\nfunction isInteractive(): boolean {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n}\n\nfunction getEndpoint(): string {\n const candidate = process.env.FARM_TELEMETRY_ENDPOINT || DEFAULT_TELEMETRY_ENDPOINT;\n try {\n const url = new URL(candidate);\n const isLocal = [\"localhost\", \"127.0.0.1\", \"::1\"].includes(url.hostname);\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && isLocal)) {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n return url.toString();\n } catch {\n return DEFAULT_TELEMETRY_ENDPOINT;\n }\n}\n\nasync function resolveState(): Promise<{\n config: FarmTelemetryConfig;\n enabled: boolean;\n active: boolean;\n source: FarmTelemetryStatus[\"source\"];\n reason?: string;\n}> {\n const { config, stored } = await readConfig();\n const environment = environmentDecision();\n const enabled = environment.enabled ?? config.enabled;\n const source =\n environment.enabled !== undefined ? \"environment\" : stored ? \"configuration\" : \"default\";\n\n if (!enabled) return { config, enabled, active: false, source, reason: environment.reason };\n if (environment.enabled === true) return { config, enabled, active: true, source };\n if (process.env.NODE_ENV === \"test\") {\n return { config, enabled, active: false, source, reason: \"test environments are skipped\" };\n }\n if (isContinuousIntegration()) {\n return { config, enabled, active: false, source, reason: \"CI environments are skipped\" };\n }\n if (!isInteractive()) {\n return {\n config,\n enabled,\n active: false,\n source,\n reason: \"non-interactive commands are skipped\",\n };\n }\n return { config, enabled, active: true, source };\n}\n\nexport async function getFarmTelemetryStatus(): Promise<FarmTelemetryStatus> {\n const state = await resolveState();\n return {\n enabled: state.enabled,\n active: state.active,\n source: state.source,\n endpoint: getEndpoint(),\n configFile: getFarmTelemetryConfigFile(),\n anonymousId: state.config.anonymousId,\n reason: state.reason,\n };\n}\n\nexport async function setFarmTelemetryEnabled(enabled: boolean): Promise<FarmTelemetryStatus> {\n const { config: current } = await readConfig();\n await writeConfig({\n version: TELEMETRY_SCHEMA_VERSION,\n enabled,\n noticeShown: true,\n anonymousId: enabled ? current.anonymousId || randomUUID() : undefined,\n });\n return getFarmTelemetryStatus();\n}\n\nexport async function showFarmTelemetryNotice(): Promise<void> {\n if (!isInteractive() || isContinuousIntegration() || process.env.NODE_ENV === \"test\") return;\n if (environmentDecision().enabled !== undefined) return;\n const { config } = await readConfig();\n if (config.noticeShown) return;\n process.stderr.write(\n `Farm.js collects anonymous CLI telemetry by default. Run \"farm telemetry disable\" to opt out.\\nLearn more: ${TELEMETRY_NOTICE_URL}\\n`,\n );\n await writeConfig({ ...config, noticeShown: true });\n}\n\nexport function resolveFarmTelemetryCommand(value: string): FarmTelemetryCommand | undefined {\n return (FARM_COMMANDS as readonly string[]).includes(value)\n ? (value as FarmTelemetryCommand)\n : undefined;\n}\n\nexport function resolveFarmCreateAppTelemetryCommand(\n value: string,\n): FarmCreateAppTelemetryCommand | undefined {\n return (CREATE_APP_COMMANDS as readonly string[]).includes(value)\n ? (value as FarmCreateAppTelemetryCommand)\n : undefined;\n}\n\nexport async function trackFarmCommand(input: FarmCommandTelemetryInput): Promise<void> {\n const deployTarget = allowlisted(input.deployTarget, DEPLOY_TARGETS);\n await track({\n eventType: \"command_invoked\",\n source: \"cli\",\n packageName: \"@farm.js/cli\",\n packageVersion: sanitizeVersion(input.packageVersion),\n command: input.command,\n ...(deployTarget ? { deployTarget } : {}),\n });\n}\n\nexport async function trackFarmCreateAppCommand(\n input: FarmCreateAppCommandTelemetryInput,\n): Promise<void> {\n const command = allowlisted(input.command, CREATE_APP_COMMANDS);\n if (!command) return;\n await track({\n eventType: \"command_invoked\",\n source: \"create-app\",\n packageName: \"@farm.js/create-app\",\n packageVersion: sanitizeVersion(input.packageVersion),\n command,\n });\n}\n\nexport async function trackFarmProjectCreated(\n input: FarmProjectCreatedTelemetryInput,\n): Promise<void> {\n const template = allowlisted(input.template, FARM_TEMPLATES);\n const renderer = allowlisted(input.renderer, RENDERERS);\n const packageManager = allowlisted(input.packageManager, PACKAGE_MANAGERS);\n await track({\n eventType: \"project_created\",\n source: \"create-app\",\n packageName: \"@farm.js/create-app\",\n packageVersion: sanitizeVersion(input.packageVersion),\n ...(template ? { template } : {}),\n ...(renderer ? { renderer } : {}),\n ...(packageManager ? { packageManager } : {}),\n ...(typeof input.typescript === \"boolean\" ? { typescript: input.typescript } : {}),\n ...(typeof input.installedDependencies === \"boolean\"\n ? { installedDependencies: input.installedDependencies }\n : {}),\n });\n}\n\nasync function track(event: FarmTelemetryEventInput): Promise<void> {\n try {\n const state = await resolveState();\n if (!state.active) return;\n const anonymousId = state.config.anonymousId || randomUUID();\n if (!state.config.anonymousId) {\n await writeConfig({ ...state.config, anonymousId });\n }\n const payload = {\n schemaVersion: TELEMETRY_SCHEMA_VERSION,\n eventId: randomUUID(),\n anonymousId,\n nodeMajor: Number.parseInt(process.versions.node.split(\".\")[0] || \"0\", 10),\n platform: normalizePlatform(process.platform),\n architecture: normalizeArchitecture(process.arch),\n ...event,\n } as FarmTelemetryEvent;\n await send(payload);\n } catch {\n // Telemetry is best-effort and must never make a Farm command fail.\n }\n}\n\nasync function send(payload: FarmTelemetryEvent): Promise<void> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n timeout.unref?.();\n try {\n await fetch(getEndpoint(), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: controller.signal,\n keepalive: true,\n });\n } catch {\n // Network and endpoint failures are intentionally ignored.\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction sanitizeVersion(value: string): string {\n return /^[0-9A-Za-z.+_-]{1,64}$/.test(value) ? value : \"unknown\";\n}\n\nfunction allowlisted<const T extends readonly string[]>(\n value: string | undefined,\n values: T,\n): T[number] | undefined {\n return value && (values as readonly string[]).includes(value) ? (value as T[number]) : undefined;\n}\n\nfunction normalizePlatform(value: NodeJS.Platform): FarmTelemetryEventBase[\"platform\"] {\n if (value === \"darwin\" || value === \"linux\") return value;\n if (value === \"win32\") return \"windows\";\n return \"other\";\n}\n\nfunction normalizeArchitecture(value: string): FarmTelemetryEventBase[\"architecture\"] {\n return value === \"arm64\" || value === \"x64\" ? value : \"other\";\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farm.js/cli",
3
- "version": "0.1.0-beta.52",
3
+ "version": "0.1.0-beta.54",
4
4
  "description": "CLI for Farm.js framework",
5
5
  "keywords": [
6
6
  "@farm.js/cli",
@@ -30,7 +30,7 @@
30
30
  "commander": "^11.1.0",
31
31
  "croner": "9.1.0",
32
32
  "picocolors": "^1.0.0",
33
- "@farm.js/core": "0.1.0-beta.52"
33
+ "@farm.js/core": "0.1.0-beta.54"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^20.10.5",