# `QuackDB.Server`
[🔗](https://github.com/elixir-vibe/quackdb/blob/main/lib/quack_db/server.ex#L1)

Supervises a local DuckDB Quack server process with MuonTrap.

This is a convenience for local development, tests, demos, and notebooks. It
starts the external `duckdb` executable and serves DuckDB's Quack HTTP
protocol. It is not an embedded DuckDB driver and is not required when your
Quack server runs elsewhere.

    children =
      QuackDB.Server.child_specs(
        server: [name: MyApp.DuckDB, duckdb: :managed, endpoint: "quack:localhost:9494"],
        client: [name: MyApp.QuackDB, pool_size: 5]
      )

Use `duckdb: :managed` to download and cache DuckDB's official CLI binary via
`QuackDB.Binary`. Pass `duckdb: "/path/to/duckdb"` or set
`QUACKDB_BINARY_PATH` when you want to provide the executable yourself.

`child_specs/1` generates one shared random token when neither side provides
`:token`, then injects the same token and URI into the server and client specs.

By default the server runs DuckDB directly under MuonTrap with `-interactive`
so the process stays alive after `quack_serve/2` starts. It installs and loads
the `quack` extension before serving, unless `load_quack?: false` is set. Boot
SQL is written to an Elixir-owned temporary init file by default so generated
local tokens are not embedded in the operating-system argument vector.

Startup waits until the Quack endpoint is ready. For the default DuckDB CLI
command, readiness is detected from the `quack_serve/2` result row printed to
stdout. `:poll_interval` is only the fallback probe interval for custom daemon
output handling or custom commands that do not expose that row. Probes run in
a cancellable task so daemon exits and output remain visible while HTTP waits;
the startup deadline also cancels an in-flight probe.

Startup failures report `:server_start_failed`, `:server_start_timeout`, or
`:database_locked` for recognized DuckDB file-lock conflicts. Error metadata
includes `:database`, `:uri`, `:last_error`, an `:output_tail` of at most 8 KiB,
and `:exit_reason` when the daemon exits. The retained output redacts the
server token, replaces invalid UTF-8, and truncates on a character boundary.
Explicitly configured logger callbacks still receive original output.
Capture is best-effort, newline-delimited MuonTrap output; disabling
stderr forwarding can omit diagnostics. Other secrets in custom boot output
are not automatically redacted.

Stopping this process signals the daemon; it does not run `CHECKPOINT` or
guarantee an immediately copyable database file. Preserve a remaining WAL for
recovery. Quiesce writers and explicitly checkpoint before a single-file copy,
then stop clients and the supervised server and verify OS-process termination.
A supervised server is a permanent child: use `Supervisor.terminate_child/2`
rather than `GenServer.stop/1` to stop it without automatic restart.

# `option`

```elixir
@type option() ::
  {:name, GenServer.name()}
  | {:duckdb, String.t() | :managed}
  | {:duckdb_options, keyword()}
  | {:database, String.t()}
  | {:endpoint, String.t()}
  | {:uri, String.t()}
  | {:token, String.t()}
  | {:load_quack?, boolean()}
  | {:install_quack?, boolean()}
  | {:boot_sql, String.t()}
  | {:boot_sql_source, :init_file | :cmd}
  | {:settings, keyword(QuackDB.SQL.parameter())}
  | {:global_settings, keyword(QuackDB.SQL.parameter())}
  | {:serve_options, keyword()}
  | {:recovery_mode, :no_wal_writes | String.t()}
  | {:attach_as, atom() | String.t()}
  | {:wait, boolean()}
  | {:wait_timeout, timeout()}
  | {:poll_interval, pos_integer()}
  | {:daemon_options, Keyword.t()}
  | {:daemon_command, {String.t(), [String.t()]}}
```

# `child_spec`

```elixir
@spec child_spec([option()]) :: Supervisor.child_spec()
```

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `child_specs`

```elixir
@spec child_specs(keyword()) :: [Supervisor.child_spec()]
```

Returns matching server and client child specs, in startup order.

`:server` is a list of Server options. `:client` accepts a keyword list for a
QuackDB pool, or `{module, options}` for another client such as an Ecto Repo.
The client must accept `:uri` and `:token` options. URI/token precedence is
server, then client, then generated defaults. Both specs retain the generated
credentials across restarts.

    alias QuackDB.Server

    children =
      Server.child_specs(
        server: [name: MyApp.DuckDB],
        client: {MyApp.Repo, pool_size: 2}
      )

A `:rest_for_one` supervisor can restart the client when its server restarts
and invalidates existing sessions.

# `info`

```elixir
@spec info(GenServer.server()) :: map()
```

# `os_pid`

```elixir
@spec os_pid(GenServer.server()) :: non_neg_integer() | :error
```

Returns the local MuonTrap wrapper's OS PID, not the DuckDB child PID.

This does not identify the process holding a conflicting database file lock.

# `start_link`

```elixir
@spec start_link([option()]) :: GenServer.on_start()
```

# `statistics`

```elixir
@spec statistics(GenServer.server()) :: map()
```

# `token`

```elixir
@spec token(GenServer.server()) :: String.t()
```

# `uri`

```elixir
@spec uri(GenServer.server()) :: String.t()
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
