type OwlLogLevel = "info" | "debug" | "warn" | "error"; interface OwlConfiguration { /** Owlmetry server endpoint URL */ endpoint: string; /** Client API key for a server-platform app (must start with owl_client_) */ apiKey: string; /** Service name for logging/debugging (not sent as bundle_id) */ serviceName?: string; /** Application version */ appVersion?: string; /** Enable debug logging to console.error */ debug?: boolean; /** Flush interval in milliseconds (default: 5000) */ flushIntervalMs?: number; /** Max events to buffer before auto-flush (default: 20) */ flushThreshold?: number; /** Max events in buffer before dropping oldest (default: 10000) */ maxBufferSize?: number; /** Mark events as development builds. Defaults to `process.env.NODE_ENV !== "production"` */ isDev?: boolean; /** Print events to console. Defaults to true. */ consoleLogging?: boolean; } interface LogEvent { client_event_id: string; session_id: string; user_id?: string; level: OwlLogLevel; source_module?: string; message: string; custom_attributes?: Record; experiments?: Record; environment: "backend"; app_version?: string; sdk_name: string; sdk_version: string; is_dev?: boolean; timestamp: string; } /** * Request body accepted by `POST /v1/feedback`. Mirrors * `IngestFeedbackRequest` in `@owlmetry/shared`. */ interface FeedbackSubmission { bundle_id?: string; message: string; session_id?: string | null; user_id?: string | null; submitter_name?: string | null; submitter_email?: string | null; app_version?: string; sdk_name?: string; sdk_version?: string; environment?: string; device_model?: string; os_version?: string; is_dev?: boolean; } /** Server response from `POST /v1/feedback`. */ interface FeedbackReceipt { id: string; created_at: string; } interface OwlAttachment { /** Absolute path to a file on disk. Mutually exclusive with `buffer`. */ path?: string; /** In-memory bytes. Mutually exclusive with `path`. */ buffer?: Buffer | Uint8Array; /** Filename shown on the server. Required for `buffer`; defaults to basename of `path`. */ name?: string; /** Overrides the inferred/default content type. */ contentType?: string; } type LogFn = (level: "info" | "error", message: string, attrs?: Record, userId?: string, attachments?: OwlAttachment[], sessionId?: string) => void; /** * Tracks a metric operation lifecycle (start → complete/fail/cancel). * Created by `Owl.startOperation()` or `ScopedOwl.startOperation()`. */ declare class OwlOperation { readonly trackingId: string; private metric; private startTime; private userId?; private sessionId?; private log; constructor(log: LogFn, metric: string, attrs?: Record, userId?: string, sessionId?: string); /** Complete the operation successfully. Auto-adds duration_ms. */ complete(attrs?: Record): void; /** Record a failed operation. Auto-adds duration_ms + error. */ fail(error: string, attrs?: Record): void; /** Cancel the operation. Auto-adds duration_ms. */ cancel(attrs?: Record): void; } interface SendFeedbackOptions { /** Display name the user entered. */ name?: string; /** Email the user entered. Validated server-side. */ email?: string; /** * User ID to attach to the feedback row. On a scoped logger this defaults * to the scope's userId; pass here to override or set explicitly. */ userId?: string; /** * UUID session to link to the event timeline. On a scoped logger this * defaults to the scope's sessionId; non-UUID values are ignored. */ sessionId?: string; /** * Bundle ID — only needed when forwarding feedback on behalf of a mobile * frontend whose Owlmetry app has a bundle_id set. Backend apps have no * bundle_id so this can be omitted. */ bundleId?: string; /** Override environment (default: "backend"). Validated server-side. */ environment?: string; /** Override appVersion (default: value from `configure({ appVersion })`). */ appVersion?: string; /** Device model — pass-through when forwarding from a mobile frontend. */ deviceModel?: string; /** OS version — pass-through when forwarding from a mobile frontend. */ osVersion?: string; /** Override isDev (default: value from `configure({ isDev })`). */ isDev?: boolean; } interface SendFeedbackReceipt { id: string; createdAt: string; } /** * A scoped logger instance that automatically tags a user ID and/or a session ID * on every event. Create via `Owl.withUser(userId)` or `Owl.withSession(sessionId)`. * Scopes chain: `Owl.withSession(sid).withUser(uid)` and vice versa both work. * * The session scope is typically used in a server handler to link backend events * to a client's session — e.g. read an `X-Owl-Session-Id` header sent by the * Swift SDK (`Owl.sessionId`) and scope every event in the handler to that value. */ declare class ScopedOwl { private userId?; private sessionId?; constructor(userId?: string, sessionId?: string); /** Return a new scope with the given userId, preserving any existing session scope. */ withUser(userId: string): ScopedOwl; /** * Return a new scope with the given sessionId, preserving any existing user scope. * `sessionId` should be a UUID string (as produced by `randomUUID()` or the Swift * SDK's `Owl.sessionId`). Non-UUID values are silently ignored — the returned * scope falls back to the SDK's default session ID — so untrusted client input * cannot crash a request handler. Enable `debug: true` on configure to see * warnings when invalid values are received. */ withSession(sessionId: string): ScopedOwl; info(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; debug(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; warn(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; error(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; /** * Record a named funnel step. Sends an info-level event with message `step:`. */ step(stepName: string, attributes?: Record): void; /** @deprecated Use `step()` instead. Will be removed in a future version. */ track(stepName: string, attributes?: Record): void; /** * Set custom properties on this user. Properties are merged server-side — * existing keys not in this call are preserved. Pass an empty string value * to remove a property. * * Requires a user-scoped instance — throws if the scope has no userId. */ setUserProperties(properties: Record): void; /** * Start a tracked operation. The `metric` slug should contain only lowercase letters, * numbers, and hyphens (e.g. "photo-conversion", "api-request"). Invalid characters * are auto-corrected with a warning logged in debug mode. */ startOperation(metric: string, attrs?: Record): OwlOperation; /** * Record a single-shot metric. The `metric` slug should contain only lowercase letters, * numbers, and hyphens (e.g. "onboarding", "checkout"). Invalid characters are * auto-corrected with a warning logged in debug mode. */ recordMetric(metric: string, attrs?: Record): void; /** * Forward user feedback collected from your frontend to Owlmetry. Defaults * `user_id` and `session_id` to the scope's values (override via `options`). * * Throws on failure — wrap calls in try/catch. Empty messages reject * synchronously; server-side 4xx responses surface as thrown errors with * the server's `error` field in the message. */ sendFeedback(message: string, options?: SendFeedbackOptions): Promise; } /** * Owlmetry Node.js Server SDK. * * Usage: * ``` * import { Owl } from '@owlmetry/node'; * * Owl.configure({ endpoint: 'https://...', apiKey: 'owl_client_...' }); * Owl.info('Server started'); * * const owl = Owl.withUser('user_123'); * owl.info('User logged in'); * * await Owl.shutdown(); * ``` */ declare const Owl: { configure(options: OwlConfiguration): void; info(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; debug(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; warn(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; error(message: string, attrs?: Record, options?: { attachments?: OwlAttachment[]; sessionId?: string; }): void; /** * Record a named funnel step. Sends an info-level event with message `step:`. */ step(stepName: string, attributes?: Record): void; /** @deprecated Use `step()` instead. Will be removed in a future version. */ track(stepName: string, attributes?: Record): void; /** * Set custom properties on a user. Properties are merged server-side — * existing keys not in this call are preserved. Pass an empty string value * to remove a property. */ setUserProperties(userId: string, properties: Record): void; /** * Get the assigned variant for an experiment. On first call, picks a random variant * from `options` and persists the assignment. Future calls return the stored variant * (the `options` parameter is ignored after the first assignment). */ getVariant(name: string, options: string[]): string; /** * Force a specific variant for an experiment. Persists immediately. */ setExperiment(name: string, variant: string): void; /** * Reset all experiment assignments. Persists immediately. */ clearExperiments(): void; /** * Start a tracked operation. The `metric` slug should contain only lowercase letters, * numbers, and hyphens (e.g. "photo-conversion", "api-request"). Invalid characters * are auto-corrected with a warning logged in debug mode. */ startOperation(metric: string, attrs?: Record): OwlOperation; /** * Record a single-shot metric. The `metric` slug should contain only lowercase letters, * numbers, and hyphens (e.g. "onboarding", "checkout"). Invalid characters are * auto-corrected with a warning logged in debug mode. */ recordMetric(metric: string, attrs?: Record): void; /** * Return a scoped logger that tags every event with the given userId. The scope * can be further narrowed with `.withSession(sessionId)` if needed. */ withUser(userId: string): ScopedOwl; /** * Return a scoped logger that tags every event with the given sessionId, overriding * the SDK's default per-process session ID. Use this in a request handler to link * backend events to a client's session — typically by propagating the client's * session ID (e.g. Swift SDK `Owl.sessionId`) through a request header. * * `sessionId` should be a UUID string. Non-UUID values are silently ignored * (the returned scope falls back to the SDK's default session ID) so untrusted * client input cannot crash a request handler. Enable `debug: true` on configure * to see warnings when invalid values are received. Chainable with `.withUser()`. */ withSession(sessionId: string): ScopedOwl; /** * Forward user feedback collected from your frontend to Owlmetry. * * Use this when your own frontend (web form, chat widget, support page) * sends feedback to your Node server and you want it captured in the * Owlmetry feedback tracker. * * Throws on failure — wrap calls in try/catch. Empty messages reject * synchronously; server-side 4xx responses surface as thrown errors with * the server's `error` field in the message. * * @param message The user's feedback text (trimmed, max 4000 chars). * @param options Optional metadata — submitter name/email, user/session IDs, etc. * @returns Receipt containing the new feedback id and ISO-8601 createdAt. */ sendFeedback(message: string, options?: SendFeedbackOptions): Promise; flush(): Promise; wrapHandler(handler: (...args: TArgs) => Promise): (...args: TArgs) => Promise; shutdown(): Promise; }; export { type FeedbackReceipt, type FeedbackSubmission, type LogEvent, Owl, type OwlAttachment, type OwlConfiguration, type OwlLogLevel, OwlOperation, ScopedOwl, type SendFeedbackOptions, type SendFeedbackReceipt };