import { NAuthConfig } from '../interfaces/config.interface'; import { StorageAdapter } from '../interfaces/storage-adapter.interface'; import { NAuthLogger } from '../utils/nauth-logger'; import { MFAService } from './mfa.service'; import { SocialProviderRegistry } from './social-provider-registry.service'; /** * Anonymous telemetry payload — configuration shape only. * * Contains no personal data: no IP addresses, secrets, domains, emails, * table names, or free-text configuration values. Documented publicly at * https://nauth.dev/docs/concepts/telemetry */ export interface TelemetryPayload { schemaVersion: 1; instanceId: string; event: 'boot' | 'heartbeat'; coreVersion: string; nodeMajor: number; platform: string; arch: string; nodeEnv: 'production' | 'development' | 'other'; framework: string; config: { tokenDeliveryMethod: 'json' | 'cookies' | 'hybrid'; mfa: { enabled: boolean; enforcement: 'OPTIONAL' | 'REQUIRED' | 'ADAPTIVE' | null; gracePeriodSet: boolean; allowedMethods: string[]; }; mfaProviders: string[]; socialProviders: string[]; storageAdapter: string; signupVerificationMethod: string | null; auditLogsEnabled: boolean; recaptchaEnabled: boolean; geoLocationConfigured: boolean; }; } /** * Anonymous usage telemetry (opt-out) * * Sends a small, anonymous payload describing the *shape* of the nauth * configuration (enums, booleans, and registered provider names — never * values) once at boot and once per day thereafter. The data guides * development priorities; see https://nauth.dev/docs/concepts/telemetry * for the exact payload and rationale. * * **Performance guarantees:** * - Never runs inside a request path — no middleware or handler involvement * - The boot ping is deferred and fire-and-forget; `NAuth.create()` gains no awaits * - The heartbeat timer is unref'd and never keeps the process alive * - Network failures are swallowed at debug level; this service never throws * * **Disabled automatically** when any of the following holds: * - `config.telemetry.enabled === false` * - `NAUTH_TELEMETRY_DISABLED=1` or `DO_NOT_TRACK=1` * - `CI=true` or `NODE_ENV=test` * * @example * ```typescript * const telemetry = new TelemetryService(config, storage, logger, 'express', mfaService, socialRegistry); * telemetry.sendBootPing(); * telemetry.startHeartbeat(); * // ...on shutdown: * telemetry.shutdown(); * ``` */ export declare class TelemetryService { private readonly config; private readonly storageAdapter; private readonly logger?; private readonly framework; private readonly mfaService?; private readonly socialProviderRegistry?; private heartbeatTimer?; private cachedInstanceId?; private disclosureShown; constructor(config: NAuthConfig, storageAdapter: StorageAdapter, logger?: NAuthLogger | undefined, framework?: string, mfaService?: MFAService | undefined, socialProviderRegistry?: SocialProviderRegistry | undefined); /** * Whether telemetry is active for this process. * * Evaluates the config flag and all environment opt-outs * (NAUTH_TELEMETRY_DISABLED, DO_NOT_TRACK, CI, NODE_ENV=test). * * @returns true when telemetry may be sent */ isEnabled(): boolean; /** * Send the boot ping (fire-and-forget). * * On the first boot of an install (when the anonymous instance ID is * created), a one-time disclosure notice is logged. Subsequent boots of * the same install are silent. This method returns immediately and never * throws; all work happens off the startup path. */ sendBootPing(): void; /** * Start the daily heartbeat timer. * * The timer is unref'd so it never prevents process exit. A random jitter * of up to one hour avoids synchronized pings from fleets that restart * together. No-op when telemetry is disabled. */ startHeartbeat(): void; /** * Stop the heartbeat timer. Safe to call multiple times. */ shutdown(): void; /** * Resolve the anonymous instance ID, with layered persistence: * * 1. **Storage adapter** (Redis/database) — deployment-scoped: all processes * sharing the deployment converge on one ID via an NX (set-if-absent) write. * 2. **Home-directory file** (`~/.nauth-toolkit/telemetry-instance-id`) — used * when the storage adapter is the non-persistent in-memory adapter, so * restarts on the same machine keep one ID instead of minting a new * "install" per boot. * 3. **Per-process UUID** — last resort when both stores are unavailable * (e.g. read-only filesystem); never throws. * * `isNew` is true only when this process created the ID — used to show the * disclosure notice exactly once per install. */ private resolveInstanceId; /** * File-backed instance ID under the user's home directory. Returns a * per-process UUID when the filesystem is unavailable or read-only. */ private resolveInstanceIdFromFile; /** * Build the telemetry payload from the resolved configuration and the * registered provider lists. Pure shape extraction — no values are read * beyond enums, booleans, and provider identifiers. */ private buildPayload; /** * Resolve the storage adapter class name for the payload. * * Lazy wrappers (used by the NestJS module and the core storage factory) * would otherwise report 'LazyStorageAdapter' for every install; when the * wrapper has an initialized inner adapter, its class name is reported * instead. By the time the payload is built the instance-ID lookup has * already gone through the adapter, so the inner adapter exists. */ private storageAdapterName; /** * POST the payload to the telemetry endpoint with a hard timeout. * All failures are swallowed (debug log only) — telemetry must be * invisible when it fails. */ private send; } //# sourceMappingURL=telemetry.service.d.ts.map