{"version":3,"file":"postinstall.cjs","names":["isTelemetryDisabled","path","ciInfoIsCI","ciInfoId","isTruthyEnv","normalizeProjectIdentity","getPostHogConfig","TELEMETRY_REQUEST_TIMEOUT_MS"],"sources":["../src/telemetry/install.ts","../src/postinstall.ts"],"sourcesContent":["/**\n * Installation telemetry disclosure\n *\n * Sent during package postinstall unless telemetry is disabled:\n * - A random installation ID and a salted SHA-256 project ID\n * - Lang Core, Node.js, OS, architecture, and package-manager versions\n * - CI provider category, Docker status, project-ID source category, and schema version\n *\n * The JSON payload contains no direct PII or application-user data. It never includes\n * names, email addresses, usernames, raw Git origins, repository or project names,\n * filesystem paths, branches, commits, credentials, environment values, source code,\n * prompts, messages, generated output, component or tool definitions, errors, logs,\n * stack traces, routes, or UI interactions. As with any HTTP request, the telemetry\n * proxy and PostHog can observe the source IP as transport metadata; the script does\n * not read it or add it to the payload.\n */\nimport { id as ciInfoId, isCI as ciInfoIsCI } from \"ci-info\";\nimport { execFileSync } from \"node:child_process\";\nimport { createHash, randomBytes, randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, type WriteFileOptions } from \"node:fs\";\nimport { homedir, release } from \"node:os\";\nimport path from \"node:path\";\nimport {\n  getPostHogConfig,\n  isTelemetryDisabled,\n  isTruthyEnv,\n  normalizeProjectIdentity,\n  TELEMETRY_REQUEST_TIMEOUT_MS,\n  TELEMETRY_SCHEMA_VERSION,\n} from \"./shared\";\n\nexport { isTelemetryDisabled, isTruthyEnv, normalizeProjectIdentity };\n\nexport const INSTALL_EVENT = \"openui_lang_core_installed\";\n\nexport type ProjectIdSource = \"git_origin\" | \"repository_url\" | \"install_root\";\nexport type PackageManagerName = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" | \"unknown\";\n\nexport interface InstallTelemetryProperties extends Record<string, unknown> {\n  telemetry_schema_version: number;\n  project_id: string;\n  project_id_source: ProjectIdSource;\n  lang_core_version: string;\n  node_version: string;\n  system_platform: string;\n  system_release: string;\n  system_architecture: string;\n  package_manager: PackageManagerName;\n  package_manager_version?: string;\n  ci: boolean;\n  ci_name?: string;\n  is_docker: boolean;\n}\n\nexport interface InstallTelemetryPayload {\n  distinctId: string;\n  event: typeof INSTALL_EVENT;\n  properties: InstallTelemetryProperties;\n}\n\nexport interface InstallTelemetryIO {\n  cwd(): string;\n  homedir(): string;\n  readFile(file: string): string;\n  writeFile(file: string, contents: string, options?: WriteFileOptions): void;\n  mkdir(directory: string): void;\n  getGitOrigin(projectRoot: string): string | undefined;\n  platform: string;\n  architecture: string;\n  release(): string;\n  randomUUID(): string;\n  randomHex(bytes: number): string;\n  isDocker(): boolean;\n  stdout(message: string): void;\n  stderr(message: string): void;\n}\n\nexport type InstallTelemetrySender = (\n  payload: InstallTelemetryPayload,\n  env: NodeJS.ProcessEnv,\n) => Promise<void>;\n\nexport interface RunInstallTelemetryOptions {\n  env?: NodeJS.ProcessEnv;\n  io?: Partial<InstallTelemetryIO>;\n  send?: InstallTelemetrySender;\n}\n\nexport type RunInstallTelemetryResult =\n  | { status: \"disabled\" }\n  | { status: \"debug\"; payload: InstallTelemetryPayload }\n  | { status: \"sent\"; payload: InstallTelemetryPayload }\n  | { status: \"failed\"; payload?: InstallTelemetryPayload };\n\ninterface StoredTelemetryState extends Record<string, unknown> {\n  distinctId: string;\n  projectSalt: string;\n  langCorePostinstallNoticeShown?: boolean;\n}\n\ninterface ProjectIdentity {\n  value: string;\n  source: ProjectIdSource;\n}\n\nconst INSTALL_NOTICE =\n  \"\\n◆ OpenUI Lang Core sends pseudonymous installation telemetry to PostHog.\\n\" +\n  \"  It includes a salted project ID, OpenUI/Node/OS/package-manager metadata, and the network IP observed by PostHog.\\n\" +\n  \"  It does not send repository URLs, paths, source code, prompts, errors, or application data.\\n\" +\n  \"  Disable it with OPENUI_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1.\\n\\n\";\n\nexport function hashProjectIdentity(salt: string, projectIdentity: string): string {\n  return createHash(\"sha256\").update(salt).update(\"\\0\").update(projectIdentity).digest(\"hex\");\n}\n\nexport function detectPackageManager(env: NodeJS.ProcessEnv): {\n  name: PackageManagerName;\n  version?: string;\n} {\n  const userAgent = env[\"npm_config_user_agent\"]?.trim() ?? \"\";\n  const match = userAgent.match(/^(npm|pnpm|yarn|bun)\\/([^\\s]+)/i);\n  if (!match) return { name: \"unknown\" };\n\n  const name = match[1]!.toLowerCase() as Exclude<PackageManagerName, \"unknown\">;\n  const version = match[2]!.slice(0, 64);\n  return version ? { name, version } : { name };\n}\n\nexport async function runInstallTelemetry(\n  options: RunInstallTelemetryOptions = {},\n): Promise<RunInstallTelemetryResult> {\n  const env = options.env ?? process.env;\n  if (isTelemetryDisabled(env)) return { status: \"disabled\" };\n\n  let payload: InstallTelemetryPayload | undefined;\n  try {\n    const io = createInstallTelemetryIO(options.io);\n    const stateFile = getTelemetryStateFile(env, io);\n    const state = loadOrCreateState(stateFile, io);\n    const projectRoot = path.resolve(env[\"INIT_CWD\"] || io.cwd());\n    const projectIdentity = resolveProjectIdentity(projectRoot, env, io);\n    const packageManager = detectPackageManager(env);\n\n    payload = {\n      distinctId: state.distinctId,\n      event: INSTALL_EVENT,\n      properties: {\n        telemetry_schema_version: TELEMETRY_SCHEMA_VERSION,\n        project_id: hashProjectIdentity(state.projectSalt, projectIdentity.value),\n        project_id_source: projectIdentity.source,\n        lang_core_version:\n          env[\"OPENUI_LANG_CORE_PACKAGE_VERSION\"] || env[\"npm_package_version\"] || \"unknown\",\n        node_version: process.version,\n        system_platform: io.platform,\n        system_release: io.release(),\n        system_architecture: io.architecture,\n        package_manager: packageManager.name,\n        ...(packageManager.version ? { package_manager_version: packageManager.version } : {}),\n        ci: ciInfoIsCI,\n        ...(ciInfoId ? { ci_name: ciInfoId } : {}),\n        is_docker: io.isDocker(),\n      },\n    };\n\n    if (!state.langCorePostinstallNoticeShown) {\n      io.stderr(INSTALL_NOTICE);\n      state.langCorePostinstallNoticeShown = true;\n    }\n    persistState(stateFile, state, io);\n\n    if (isTruthyEnv(env[\"OPENUI_TELEMETRY_DEBUG\"])) {\n      io.stdout(`[OpenUI telemetry debug]\\n${JSON.stringify(payload, null, 2)}\\n`);\n      return { status: \"debug\", payload };\n    }\n\n    await (options.send ?? sendToPostHog)(payload, env);\n    return { status: \"sent\", payload };\n  } catch {\n    return { status: \"failed\", ...(payload ? { payload } : {}) };\n  }\n}\n\nfunction createInstallTelemetryIO(overrides: Partial<InstallTelemetryIO> = {}): InstallTelemetryIO {\n  return {\n    cwd: () => process.cwd(),\n    homedir,\n    readFile: (file) => readFileSync(file, \"utf8\"),\n    writeFile: (file, contents, options) => writeFileSync(file, contents, options),\n    mkdir: (directory) => mkdirSync(directory, { recursive: true, mode: 0o700 }),\n    getGitOrigin: defaultGetGitOrigin,\n    platform: process.platform,\n    architecture: process.arch,\n    release,\n    randomUUID,\n    randomHex: (bytes) => randomBytes(bytes).toString(\"hex\"),\n    isDocker: defaultIsDocker,\n    stdout: (message) => process.stdout.write(message),\n    stderr: (message) => process.stderr.write(message),\n    ...overrides,\n  };\n}\n\nfunction getTelemetryStateFile(env: NodeJS.ProcessEnv, io: InstallTelemetryIO): string {\n  const configRoot = env[\"XDG_CONFIG_HOME\"] || path.join(io.homedir(), \".config\");\n  return path.join(configRoot, \"openui\", \"telemetry.json\");\n}\n\nfunction loadOrCreateState(stateFile: string, io: InstallTelemetryIO): StoredTelemetryState {\n  let stored: Record<string, unknown> = {};\n  try {\n    const parsed = JSON.parse(io.readFile(stateFile)) as unknown;\n    if (isRecord(parsed)) stored = parsed;\n  } catch {\n    // Missing or corrupt state is replaced with a new best-effort state.\n  }\n\n  return {\n    ...stored,\n    distinctId:\n      typeof stored[\"distinctId\"] === \"string\" && stored[\"distinctId\"]\n        ? stored[\"distinctId\"]\n        : io.randomUUID(),\n    projectSalt:\n      typeof stored[\"projectSalt\"] === \"string\" && stored[\"projectSalt\"]\n        ? stored[\"projectSalt\"]\n        : io.randomHex(16),\n    langCorePostinstallNoticeShown: stored[\"langCorePostinstallNoticeShown\"] === true,\n  };\n}\n\nfunction persistState(\n  stateFile: string,\n  state: StoredTelemetryState,\n  io: InstallTelemetryIO,\n): void {\n  try {\n    io.mkdir(path.dirname(stateFile));\n    io.writeFile(stateFile, JSON.stringify(state), { mode: 0o600 });\n  } catch {\n    // Read-only or ephemeral environments use the in-memory state for this run.\n  }\n}\n\nfunction resolveProjectIdentity(\n  projectRoot: string,\n  env: NodeJS.ProcessEnv,\n  io: InstallTelemetryIO,\n): ProjectIdentity {\n  const gitOrigin = io.getGitOrigin(projectRoot)?.trim();\n  if (gitOrigin) {\n    return { value: normalizeProjectIdentity(gitOrigin), source: \"git_origin\" };\n  }\n\n  const repositoryUrl = env[\"REPOSITORY_URL\"]?.trim();\n  if (repositoryUrl) {\n    return {\n      value: normalizeProjectIdentity(repositoryUrl),\n      source: \"repository_url\",\n    };\n  }\n\n  return { value: projectRoot, source: \"install_root\" };\n}\n\nfunction defaultGetGitOrigin(projectRoot: string): string | undefined {\n  try {\n    return execFileSync(\"git\", [\"-C\", projectRoot, \"config\", \"--get\", \"remote.origin.url\"], {\n      encoding: \"utf8\",\n      stdio: [\"ignore\", \"pipe\", \"ignore\"],\n      timeout: 1000,\n    }).trim();\n  } catch {\n    return undefined;\n  }\n}\n\nfunction defaultIsDocker(): boolean {\n  if (existsSync(\"/.dockerenv\")) return true;\n  try {\n    return /docker|containerd|kubepods/i.test(readFileSync(\"/proc/self/cgroup\", \"utf8\"));\n  } catch {\n    return false;\n  }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nasync function sendToPostHog(\n  payload: InstallTelemetryPayload,\n  env: NodeJS.ProcessEnv,\n): Promise<void> {\n  const postHog = getPostHogConfig(env);\n  const response = await fetch(postHog.captureUrl, {\n    method: \"POST\",\n    headers: { \"content-type\": \"application/json\" },\n    body: JSON.stringify({\n      api_key: postHog.apiKey,\n      event: payload.event,\n      properties: {\n        distinct_id: payload.distinctId,\n        ...payload.properties,\n      },\n    }),\n    signal: AbortSignal.timeout(TELEMETRY_REQUEST_TIMEOUT_MS),\n  });\n\n  if (!response.ok) throw new Error(`PostHog capture failed: ${response.status}`);\n}\n","import { runInstallTelemetry } from \"./telemetry/install\";\n\nvoid runInstallTelemetry().catch(() => {\n  // The lifecycle entry must always resolve successfully.\n});\n"],"mappings":"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"}