# `Chronicle.Connections.ConnectionString`
[🔗](https://github.com/Cratis/Chronicle.Elixir/blob/main/lib/chronicle/connections/connection_string.ex#L4)

Parses and formats Chronicle connection strings.

Chronicle connection strings use the `chronicle://` or `chronicle+srv://` scheme:

    chronicle://localhost:35000
    chronicle://client-id:client-secret@server:35000
    chronicle://server:35000?apiKey=my-key

## Multiple hosts

A `chronicle://` connection string may list more than one host, comma-separated.
Every configured host is a candidate the load balancer can pick between (see
`Chronicle.Connections.Connection`):

    chronicle://host1:35000,host2:35000,host3:35000
    chronicle://client-id:secret@host1:35000,host2:35000

IPv6 literals must use bracket notation, exactly like standard URLs:

    chronicle://[::1]:35000
    chronicle://[2001:db8::1]:35000,[2001:db8::2]:35000

A host without an explicit port uses the default (`35000`).

## DNS SRV discovery

`chronicle+srv://` resolves its single host to a set of Chronicle server
addresses via a DNS SRV lookup (query name `_chronicle._tcp.<host>`) instead of
listing hosts explicitly. It is re-resolved on every connect/reconnect attempt,
so membership changes are picked up automatically:

    chronicle+srv://my-chronicle-service

A `chronicle+srv://` connection string supports only a single host; use
`srvNameServer` to query a specific DNS server instead of the system resolver.

## Authentication

Two authentication modes are supported:

  * **Client credentials** — provide username and password in the URL userinfo:
    `chronicle://client-id:secret@host:35000`
  * **API key** — provide an `apiKey` query parameter:
    `chronicle://host:35000?apiKey=my-key`

## Query Parameters

  * `apiKey` — API key for authentication
  * `disableTls` — set to `"true"` to disable TLS (only for connecting through
    something else that terminates TLS for you, such as a plaintext-terminating
    proxy; the Chronicle kernel requires TLS on its single port, including in
    development)
  * `skipTlsValidation` — set to `"false"` to require full TLS certificate
    chain validation against the system trust store. Distinct from
    `disableTls`: TLS stays on either way, this only controls whether the
    chain is validated. Defaults to `true` — a Chronicle kernel commonly
    serves an auto-generated self-signed certificate, so validation is
    skipped unless explicitly turned on.
  * `certificatePath` — path to a client certificate file
  * `certificatePassword` — password for the client certificate
  * `loadBalancer` — strategy used to pick among multiple hosts (or
    SRV-resolved addresses): `"least-connections"` (default), `"round-robin"`,
    or `"random"`. See `Chronicle.Connections.LoadBalancer`.
  * `srvNameServer` — for `chronicle+srv://`, a specific DNS server
    (`"host"` or `"host:port"`) to query instead of the system resolver.

## Examples

    iex> cs = Chronicle.Connections.ConnectionString.default()
    iex> Chronicle.Connections.ConnectionString.server_address(cs).host
    "localhost"

    iex> cs = Chronicle.Connections.ConnectionString.parse("chronicle://localhost:35000?disableTls=true")
    iex> cs.disable_tls
    true

# `load_balancer_strategy`

```elixir
@type load_balancer_strategy() :: :least_connections | :round_robin | :random
```

# `t`

```elixir
@type t() :: %Chronicle.Connections.ConnectionString{
  api_key: String.t() | nil,
  auth_port: non_neg_integer() | nil,
  certificate_password: String.t() | nil,
  certificate_path: String.t() | nil,
  disable_tls: boolean(),
  load_balancer: load_balancer_strategy(),
  password: String.t() | nil,
  query_parameters: %{optional(String.t()) =&gt; String.t()},
  scheme: String.t(),
  server_addresses: [Chronicle.Connections.ConnectionString.ServerAddress.t()],
  skip_tls_validation: boolean(),
  srv_name_server: String.t() | nil,
  username: String.t() | nil
}
```

# `authentication_mode`

```elixir
@spec authentication_mode(t()) :: :client_credentials | :api_key | :none
```

Returns the configured authentication mode for the connection string.

Returns `:client_credentials` if username and password are set,
`:api_key` if an API key is set, or `:none` if no authentication is configured.

Raises `ArgumentError` if both client credentials and API key are specified.

## Examples

    iex> cs = Chronicle.Connections.ConnectionString.parse("chronicle://user:pass@server:35000")
    iex> Chronicle.Connections.ConnectionString.authentication_mode(cs)
    :client_credentials

# `default`

```elixir
@spec default() :: t()
```

Returns the default local development connection string without authentication.

Connects to `localhost:35000` with no TLS or credentials.

# `development`

```elixir
@spec development() :: t()
```

Returns the Chronicle development connection string with default credentials.

Uses the built-in development client ID and secret for a local Chronicle instance.

# `format`

```elixir
@spec format(t()) :: String.t()
```

Converts the connection string struct back to its URI string representation.

## Examples

    iex> cs = Chronicle.Connections.ConnectionString.default()
    iex> Chronicle.Connections.ConnectionString.format(cs)
    "chronicle://localhost:35000"

# `insecure_remote?`

```elixir
@spec insecure_remote?(t()) :: boolean()
```

Whether the connection encrypts traffic but does not verify who it is talking to, to a host
that is not the local machine.

That is the default (`skipTlsValidation` is `true`), which is convenient for development and
wrong for production: anyone who can intercept the traffic can impersonate the kernel and read
the credentials. The client logs a warning for it at startup.

# `parse`

```elixir
@spec parse(String.t()) :: t()
```

Parses a Chronicle connection string into a `ConnectionString` struct.

Raises `ArgumentError` if the connection string is malformed.

## Examples

    iex> cs = Chronicle.Connections.ConnectionString.parse("chronicle://server:35000?apiKey=abc")
    iex> cs.api_key
    "abc"

# `server_address`

```elixir
@spec server_address(t()) ::
  Chronicle.Connections.ConnectionString.ServerAddress.t() | nil
```

Returns the first configured server address.

Provided as a convenience for callers that only need a single address — such
as the OAuth2 token endpoint, which authenticates against the first
configured host rather than the address the load balancer eventually picks
for the gRPC channel itself. Multi-host and `chronicle+srv://` connection
strings still resolve and select among every address for the channel; see
`Chronicle.Connections.Connection` and `Chronicle.Connections.LoadBalancer`.

# `with_api_key`

```elixir
@spec with_api_key(t(), String.t()) :: t()
```

Returns a new connection string with the given API key.

Removes any existing client credentials.

# `with_credentials`

```elixir
@spec with_credentials(t(), String.t(), String.t()) :: t()
```

Returns a new connection string with the given client credentials.

Removes any existing API key.

---

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