Ada SDK for Elixir
The client process represents one authenticated namespace. Principal structs are lightweight local facades over the client's shared channel and its single lazy, persistent event, signal, and job streams.
Installation
Add the package to mix.exs:
{:ada_sdk, "~> 0.0.1"}
The API key authenticates the entire namespace. Start the client only in a trusted backend supervision tree.
Backend client
{:ok, ada} =
AdaSdk.Client.start_link(
endpoint: "memory.example.com:443",
api_key: System.fetch_env!("ADA_API_KEY"),
streams: [
events: [replay_limit: 100],
signals: [replay_limit: 100],
jobs: [replay_limit: 100]
]
)
alice = AdaSdk.Client.principal(ada, "alice")
bob = AdaSdk.Client.principal(ada, "bob")
{:ok, stop_alice} =
AdaSdk.Events.on_memory_ingest_finished(alice, fn event ->
IO.inspect(event.document_id)
end)
{:ok, stop_bob} =
AdaSdk.Signals.on_routine_broken(bob, fn signal ->
IO.inspect(signal)
end)
{:ok, stop_job} =
AdaSdk.Jobs.on_progressed(alice, fn event ->
IO.inspect(event)
end)
:ok = stop_alice.()
:ok = stop_alice.()
:ok = stop_bob.()
:ok = stop_job.()
:ok = AdaSdk.Client.close(ada)
Every event has a dedicated registration function with an exact protobuf payload typespec and runtime arity validation. Each registration returns an idempotent synchronous unsubscribe function. There is no public open, separate stream handle, generator, or iterator, and listener removal never closes the namespace stream.
Unary calls are strictly typed functions under AdaSdk.Ingest, AdaSdk.Recall, AdaSdk.Documents, AdaSdk.Jobs, AdaSdk.Data, and AdaSdk.Summary; every call requires an AdaSdk.Principal. Root responsibilities are principal creation, lifecycle registration, browser-session minting, and shutdown.
For example:
{:ok, accepted} =
AdaSdk.Ingest.ingest(alice, %Ada.V1.IngestRequest{document: document})
{:ok, status} =
AdaSdk.Documents.get_status(
alice,
%Ada.V1.GetDocumentStatusRequest{document_id: document_id}
)
The facade overwrites principal_id. Public-event and signal catalogs remain on the root through AdaSdk.Client.get_public_event_catalog/1 and AdaSdk.Client.get_signal_catalog/1.
Replay and reconnect configuration belongs under the root :streams option. Each category accepts :after_event_id, :replay_limit, :initial_delay_ms, :max_delay_ms, and :max_reconnect_attempts. Lifecycle callbacks remain strictly typed:
{:ok, stop_cursor} =
AdaSdk.Lifecycle.on_cursor(ada, fn info ->
save_cursor(info.stream, info.event_id, info.principal_id)
end)
{:ok, stop_terminal} =
AdaSdk.Lifecycle.on_terminal(ada, fn info ->
report_failure(info.stream, info.error)
end)
AdaSdk.Client.close/1 is idempotent and owns graceful shutdown. The Elixir package is backend-only: never place a namespace API key in a browser. Mint a short-lived principal session on the backend and use the TypeScript gRPC-Web client for browser access.