create static method

Future<PeekApiClient> create(
  1. PeekApiOptions options
)

Creates a new PeekAPI client, validates options, and starts the background flush timer.

Throws ArgumentError if the API key or endpoint is invalid.

Implementation

static Future<PeekApiClient> create(PeekApiOptions options) async {
  // Validate API key
  if (options.apiKey.isEmpty) {
    throw ArgumentError('apiKey must not be empty');
  }
  if (options.apiKey.contains('\r') || options.apiKey.contains('\n')) {
    throw ArgumentError('apiKey must not contain CRLF characters');
  }

  // Parse and validate endpoint
  final uri = Uri.tryParse(options.endpoint);
  if (uri == null || !uri.hasScheme || !uri.hasAuthority) {
    throw ArgumentError('Invalid endpoint URL: ${options.endpoint}');
  }

  // Enforce HTTPS (HTTP only for localhost)
  if (uri.scheme == 'http' && !SsrfProtection.isLocalhost(uri.host)) {
    throw ArgumentError('HTTPS required for non-localhost endpoints');
  }

  // SSRF check
  await SsrfProtection.validateHost(uri.host);

  // Compute storage path
  final storagePath = options.storagePath ??
      DiskPersistence.defaultStoragePath(options.endpoint);

  // Create HTTP client
  final httpClient = HttpClient();
  httpClient.connectionTimeout = _sendTimeout;

  final client = PeekApiClient._(options, httpClient, storagePath, uri);

  // Load persisted events from disk
  client._loadFromDisk();

  // Start flush timer
  client._flushTimer = Timer.periodic(options.flushInterval, (_) {
    client._tick();
  });

  // Register shutdown hooks
  client._registerShutdownHooks();

  if (options.debug) {
    stderr.writeln(
        '[PeekAPI] Client initialized (endpoint: ${options.endpoint})');
  }

  return client;
}