@farm.js/cli 0.1.0-beta.53 → 0.1.0-beta.55
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/bin/farm.js +18 -0
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -6
- package/dist/index.mjs.map +1 -1
- package/dist/telemetry.js +1 -0
- package/dist/telemetry.js.map +1 -1
- package/dist/telemetry.mjs +1 -0
- package/dist/telemetry.mjs.map +1 -1
- package/package.json +2 -2
package/dist/telemetry.js
CHANGED
package/dist/telemetry.js.map
CHANGED
|
@@ -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 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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"}
|
|
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 \"start\",\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/dist/telemetry.mjs
CHANGED
package/dist/telemetry.mjs.map
CHANGED
|
@@ -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 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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"}
|
|
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 \"start\",\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.
|
|
3
|
+
"version": "0.1.0-beta.55",
|
|
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.
|
|
33
|
+
"@farm.js/core": "0.1.0-beta.55"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^20.10.5",
|