Class: Leash::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/leash/client.rb

Overview

Unified Leash client — namespaces for ‘auth`, `env`, `integrations`. Ruby mirror of `leash-sdk-ts/src/leash.ts` and `leash-sdk-python/leash/client.py`.

Construction is server-only in 0.4 and requires a request object:

leash = Leash.new(request: request)        # Rails / Sinatra / Hanami / Rack hash
user = leash.auth.user                     # Leash::User or nil
key  = leash.env.get("OPENAI_API_KEY")     # String or nil
msgs = leash.integrations.gmail.list_messages(max_results: 5)

Authentication precedence (mirror TS / Python / Go exactly):

1. `LEASH_API_KEY` env var (or explicit `api_key:` constructor arg)
2. `Authorization: Bearer <jwt>` header on the request — used for
   `auth.user` AND as an env-read fallback (when no API key), but
   NEVER forwarded on integration POSTs
3. `leash-auth` cookie from the request

The Bearer fallback for env reads is documented here per the Go-reviewer callout: when the constructor sees no ‘LEASH_API_KEY` but does see an inbound `Authorization: Bearer …`, the bearer JWT is used as the API key for the platform’s ‘/api/apps/me/secrets/` endpoint. The bearer is still suppressed on integration POSTs (Critical #1 in the 0.4 plan).

Defined Under Namespace

Classes: AuthFacade

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request:, platform_url: nil, api_key: nil, transport: nil) ⇒ Client

Returns a new instance of Client.

Parameters:

  • request (Object, Hash)

    any Rack-conforming request (Rails ‘ActionDispatch::Request`, Sinatra `Sinatra::Request`, Hanami, a plain Rack `env` hash, or anything quacking with `.cookies` / `.env`).

  • platform_url (String, nil) (defaults to: nil)

    override the platform base URL. Defaults to ‘LEASH_PLATFORM_URL` env var or `leash.build`.

  • api_key (String, nil) (defaults to: nil)

    explicit ‘LEASH_API_KEY` override.

  • transport (Leash::Transport, nil) (defaults to: nil)

    inject a transport (handy for tests). When omitted, a default ‘Net::HTTP`-backed transport is built.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/leash/client.rb', line 57

def initialize(request:, platform_url: nil, api_key: nil, transport: nil)
  if request.nil?
    raise Error.new(
      "Leash requires a request object in server environments.",
      code: "NO_REQUEST_SERVER_CONSTRUCT",
      action: "Pass request: req to Leash.new in your route handler.",
      see_also: "https://leash.build/docs/sdk"
    )
  end

  @request = request
  @platform_url = (platform_url || ENV["LEASH_PLATFORM_URL"] || DEFAULT_PLATFORM_URL)
                  .to_s.sub(%r{/+\z}, "")

  # Auth precedence: explicit api_key > LEASH_API_KEY env > bearer header > cookie.
  env_api_key = ENV["LEASH_API_KEY"]
  env_api_key = nil if env_api_key && env_api_key.empty?
  @explicit_api_key = api_key || env_api_key

  @bearer_token = Auth.extract_bearer_token(request)
  @cookie_value = Auth.extract_cookie(request)

  # Bearer→env fallback: when no app key is present, the inbound user
  # JWT is used to authenticate env reads to the platform. NEVER used
  # as `X-API-Key` on integration POSTs (see Transport docstring).
  @env_api_key = @explicit_api_key || @bearer_token

  @transport = transport || Transport.new(
    platform_url: @platform_url,
    api_key: @explicit_api_key,
    cookie_value: @cookie_value
  )

  @auth = AuthFacade.new(request)
  @env = Env.new(
    platform_url: @platform_url,
    api_key: @env_api_key,
    transport: @transport
  )
  @integrations = Integrations::Namespace.new(@transport)
end

Instance Attribute Details

#authAuth (readonly)

Returns:



44
45
46
# File 'lib/leash/client.rb', line 44

def auth
  @auth
end

#bearer_tokenObject (readonly)



100
101
102
# File 'lib/leash/client.rb', line 100

def bearer_token
  @bearer_token
end


100
101
102
# File 'lib/leash/client.rb', line 100

def cookie_value
  @cookie_value
end

#envLeash::Env (readonly)

Returns:



41
42
43
# File 'lib/leash/client.rb', line 41

def env
  @env
end

#explicit_api_keyObject (readonly)



100
101
102
# File 'lib/leash/client.rb', line 100

def explicit_api_key
  @explicit_api_key
end

#integrationsLeash::Integrations::Namespace (readonly)



38
39
40
# File 'lib/leash/client.rb', line 38

def integrations
  @integrations
end

#platform_urlString (readonly)

Returns:

  • (String)


47
48
49
# File 'lib/leash/client.rb', line 47

def platform_url
  @platform_url
end