leash-sdk 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/leash.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "leash/version"
4
- require_relative "leash/integrations"
4
+ require_relative "leash/errors"
5
+ require_relative "leash/types"
5
6
  require_relative "leash/auth"
7
+ require_relative "leash/transport"
8
+ require_relative "leash/env"
9
+ require_relative "leash/integrations"
10
+ require_relative "leash/client"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leash-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leash
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-05-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: jwt
@@ -24,8 +23,24 @@ dependencies:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
25
  version: '2.7'
27
- description: Access Gmail, Google Calendar, Google Drive, and more through the Leash
28
- platform proxy. No API keys needed -- uses your Leash auth token.
26
+ - !ruby/object:Gem::Dependency
27
+ name: minitest
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '5.0'
40
+ description: Server-side Leash client. Resolve the request user, read app env-vars
41
+ at runtime, and call platform integrations (Gmail, Google Calendar, Google Drive,
42
+ Linear, plus a generic escape hatch). Framework-agnostic — works with Rails, Sinatra,
43
+ Hanami, or plain Rack.
29
44
  email:
30
45
  - hello@leash.build
31
46
  executables: []
@@ -38,12 +53,17 @@ files:
38
53
  - leash-sdk.gemspec
39
54
  - lib/leash.rb
40
55
  - lib/leash/auth.rb
41
- - lib/leash/calendar.rb
42
- - lib/leash/custom_integration.rb
43
- - lib/leash/drive.rb
56
+ - lib/leash/client.rb
57
+ - lib/leash/env.rb
44
58
  - lib/leash/errors.rb
45
- - lib/leash/gmail.rb
46
59
  - lib/leash/integrations.rb
60
+ - lib/leash/integrations/base.rb
61
+ - lib/leash/integrations/calendar.rb
62
+ - lib/leash/integrations/drive.rb
63
+ - lib/leash/integrations/gmail.rb
64
+ - lib/leash/integrations/linear.rb
65
+ - lib/leash/transport.rb
66
+ - lib/leash/types.rb
47
67
  - lib/leash/version.rb
48
68
  homepage: https://github.com/leash-build/leash-sdk-ruby
49
69
  licenses:
@@ -52,7 +72,6 @@ metadata:
52
72
  homepage_uri: https://github.com/leash-build/leash-sdk-ruby
53
73
  source_code_uri: https://github.com/leash-build/leash-sdk-ruby
54
74
  changelog_uri: https://github.com/leash-build/leash-sdk-ruby/blob/main/CHANGELOG.md
55
- post_install_message:
56
75
  rdoc_options: []
57
76
  require_paths:
58
77
  - lib
@@ -60,15 +79,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
79
  requirements:
61
80
  - - ">="
62
81
  - !ruby/object:Gem::Version
63
- version: '3.0'
82
+ version: '2.7'
64
83
  required_rubygems_version: !ruby/object:Gem::Requirement
65
84
  requirements:
66
85
  - - ">="
67
86
  - !ruby/object:Gem::Version
68
87
  version: '0'
69
88
  requirements: []
70
- rubygems_version: 3.0.3.1
71
- signing_key:
89
+ rubygems_version: 4.0.11
72
90
  specification_version: 4
73
- summary: Ruby SDK for the Leash platform integrations API
91
+ summary: Unified Ruby SDK for the Leash platform — auth, env, integrations.
74
92
  test_files: []
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Leash
4
- # Client for Google Calendar operations via the Leash platform proxy.
5
- #
6
- # Not instantiated directly -- use {Integrations#calendar} instead.
7
- class CalendarClient
8
- PROVIDER = "google_calendar"
9
-
10
- # @api private
11
- def initialize(call_fn)
12
- @call = call_fn
13
- end
14
-
15
- # List all calendars accessible to the user.
16
- #
17
- # @return [Hash] hash with calendar list data
18
- def list_calendars
19
- @call.call(PROVIDER, "list-calendars", {})
20
- end
21
-
22
- # List events on a calendar.
23
- #
24
- # @param calendar_id [String, nil] calendar identifier (defaults to "primary" on the server)
25
- # @param time_min [String, nil] lower bound for event start time (RFC 3339)
26
- # @param time_max [String, nil] upper bound for event start time (RFC 3339)
27
- # @param max_results [Integer, nil] maximum number of events to return
28
- # @param single_events [Boolean, nil] whether to expand recurring events
29
- # @param order_by [String, nil] sort order (e.g. "startTime", "updated")
30
- # @return [Hash] hash with "items" list of events
31
- def list_events(calendar_id: nil, time_min: nil, time_max: nil, max_results: nil, single_events: nil, order_by: nil)
32
- params = {}
33
- params["calendarId"] = calendar_id if calendar_id
34
- params["timeMin"] = time_min if time_min
35
- params["timeMax"] = time_max if time_max
36
- params["maxResults"] = max_results if max_results
37
- params["singleEvents"] = single_events unless single_events.nil?
38
- params["orderBy"] = order_by if order_by
39
- @call.call(PROVIDER, "list-events", params)
40
- end
41
-
42
- # Create a new calendar event.
43
- #
44
- # @param summary [String] event title
45
- # @param start [Hash, String] start time -- either an RFC 3339 string or a hash
46
- # with keys "dateTime", "date", and/or "timeZone"
47
- # @param end_time [Hash, String] end time (same format as +start+)
48
- # @param calendar_id [String, nil] calendar identifier (defaults to "primary")
49
- # @param description [String, nil] event description
50
- # @param location [String, nil] event location
51
- # @param attendees [Array<Hash>, nil] list of attendee hashes (e.g. [{ "email" => "a@b.com" }])
52
- # @return [Hash] the created event object
53
- def create_event(summary:, start:, end_time:, calendar_id: nil, description: nil, location: nil, attendees: nil)
54
- params = { "summary" => summary, "start" => start, "end" => end_time }
55
- params["calendarId"] = calendar_id if calendar_id
56
- params["description"] = description if description
57
- params["location"] = location if location
58
- params["attendees"] = attendees if attendees
59
- @call.call(PROVIDER, "create-event", params)
60
- end
61
-
62
- # Get a single event by ID.
63
- #
64
- # @param event_id [String] the event identifier
65
- # @param calendar_id [String, nil] the calendar identifier
66
- # @return [Hash] the event object
67
- def get_event(event_id, calendar_id: nil)
68
- params = { "eventId" => event_id }
69
- params["calendarId"] = calendar_id if calendar_id
70
- @call.call(PROVIDER, "get-event", params)
71
- end
72
- end
73
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Leash
4
- # Untyped client for a custom integration.
5
- #
6
- # Obtained via {Integrations#integration}. Proxies requests through the
7
- # Leash platform at +/api/integrations/custom/{name}+.
8
- #
9
- # @example
10
- # stripe = client.integration("stripe")
11
- # charges = stripe.call("/v1/charges", method: "GET")
12
- class CustomIntegration
13
- # @param name [String] the custom integration name
14
- # @param call_fn [Method] internal callable that performs the HTTP request
15
- def initialize(name, call_fn)
16
- @name = name
17
- @call_fn = call_fn
18
- end
19
-
20
- # Invoke the custom integration proxy.
21
- #
22
- # @param path [String] the endpoint path to forward (e.g. "/users")
23
- # @param method [String] HTTP method (default "GET")
24
- # @param body [Hash, nil] optional JSON body to forward
25
- # @param headers [Hash, nil] optional extra headers to forward
26
- # @return [Object] the "data" field from the platform response
27
- # @raise [Leash::Error] if the platform returns a non-success response
28
- def call(path, method: "GET", body: nil, headers: nil)
29
- @call_fn.call(@name, path, method, body, headers)
30
- end
31
- end
32
- end
data/lib/leash/drive.rb DELETED
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Leash
4
- # Client for Google Drive operations via the Leash platform proxy.
5
- #
6
- # Not instantiated directly -- use {Integrations#drive} instead.
7
- class DriveClient
8
- PROVIDER = "google_drive"
9
-
10
- # @api private
11
- def initialize(call_fn)
12
- @call = call_fn
13
- end
14
-
15
- # List files in the user's Drive.
16
- #
17
- # @param query [String, nil] Drive search query (Google Drive API query syntax)
18
- # @param max_results [Integer, nil] maximum number of files to return
19
- # @param folder_id [String, nil] restrict to files within a specific folder
20
- # @return [Hash] hash with "files" list
21
- def list_files(query: nil, max_results: nil, folder_id: nil)
22
- params = {}
23
- params["query"] = query if query
24
- params["maxResults"] = max_results if max_results
25
- params["folderId"] = folder_id if folder_id
26
- @call.call(PROVIDER, "list-files", params)
27
- end
28
-
29
- # Get file metadata by ID.
30
- #
31
- # @param file_id [String] the file identifier
32
- # @return [Hash] the file metadata object
33
- def get_file(file_id)
34
- @call.call(PROVIDER, "get-file", { "fileId" => file_id })
35
- end
36
-
37
- # Search files using a query string.
38
- #
39
- # @param query [String] search query (Google Drive API query syntax)
40
- # @param max_results [Integer, nil] maximum number of results
41
- # @return [Hash] hash with "files" list
42
- def search_files(query, max_results: nil)
43
- params = { "query" => query }
44
- params["maxResults"] = max_results if max_results
45
- @call.call(PROVIDER, "search-files", params)
46
- end
47
- end
48
- end
data/lib/leash/gmail.rb DELETED
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Leash
4
- # Client for Gmail operations via the Leash platform proxy.
5
- #
6
- # Not instantiated directly -- use {Integrations#gmail} instead.
7
- class GmailClient
8
- PROVIDER = "gmail"
9
-
10
- # @api private
11
- def initialize(call_fn)
12
- @call = call_fn
13
- end
14
-
15
- # List messages in the user's mailbox.
16
- #
17
- # @param query [String, nil] Gmail search query (e.g. "from:user@example.com")
18
- # @param max_results [Integer] maximum number of messages to return
19
- # @param label_ids [Array<String>, nil] filter by label IDs (e.g. ["INBOX"])
20
- # @param page_token [String, nil] token for fetching the next page of results
21
- # @return [Hash] hash with "messages", "nextPageToken", and "resultSizeEstimate"
22
- def list_messages(query: nil, max_results: 20, label_ids: nil, page_token: nil)
23
- params = { "maxResults" => max_results }
24
- params["query"] = query if query
25
- params["labelIds"] = label_ids if label_ids
26
- params["pageToken"] = page_token if page_token
27
- @call.call(PROVIDER, "list-messages", params)
28
- end
29
-
30
- # Get a single message by ID.
31
- #
32
- # @param message_id [String] the message ID
33
- # @param format [String] response format ("full", "metadata", "minimal", "raw")
34
- # @return [Hash] the full message object
35
- def get_message(message_id, format: "full")
36
- @call.call(PROVIDER, "get-message", { "messageId" => message_id, "format" => format })
37
- end
38
-
39
- # Send an email message.
40
- #
41
- # @param to [String] recipient email address
42
- # @param subject [String] email subject line
43
- # @param body [String] email body text
44
- # @param cc [String, nil] CC recipient(s)
45
- # @param bcc [String, nil] BCC recipient(s)
46
- # @return [Hash] the sent message metadata
47
- def send_message(to:, subject:, body:, cc: nil, bcc: nil)
48
- params = { "to" => to, "subject" => subject, "body" => body }
49
- params["cc"] = cc if cc
50
- params["bcc"] = bcc if bcc
51
- @call.call(PROVIDER, "send-message", params)
52
- end
53
-
54
- # Search messages using a Gmail query string.
55
- #
56
- # @param query [String] Gmail search query
57
- # @param max_results [Integer] maximum number of results to return
58
- # @return [Hash] hash with "messages", "nextPageToken", and "resultSizeEstimate"
59
- def search_messages(query, max_results: 20)
60
- @call.call(PROVIDER, "search-messages", { "query" => query, "maxResults" => max_results })
61
- end
62
-
63
- # List all labels in the user's mailbox.
64
- #
65
- # @return [Hash] hash with "labels" list
66
- def list_labels
67
- @call.call(PROVIDER, "list-labels", {})
68
- end
69
- end
70
- end