README.md in seam-2.0.0a2 vs README.md in seam-2.0.0b0
- old
+ new
@@ -5,20 +5,340 @@
SDK for the Seam API written in Ruby.
## Description
-TODO
+[Seam](https://seam.co) makes it easy to integrate IoT devices with your applications.
+This is an official SDK for the Seam API.
+Please refer to the official [Seam Docs](https://docs.seam.co/latest/) to get started.
+Parts of this SDK are generated from always up-to-date type information
+provided by [@seamapi/types](https://github.com/seamapi/types/).
+This ensures all API methods, request shapes, and response shapes are
+accurate and fully typed.
+
+<!-- toc -->
+
+- [Installation](#installation)
+- [Usage](#usage)
+ - [Examples](#examples)
+ - [List devices](#list-devices)
+ - [Unlock a door](#unlock-a-door)
+ - [Authentication Method](#authentication-method)
+ - [API Key](#api-key)
+ - [Personal Access Token](#personal-access-token)
+ - [Action Attempts](#action-attempts)
+ - [Interacting with Multiple Workspaces](#interacting-with-multiple-workspaces)
+ - [Webhooks](#webhooks)
+ - [Advanced Usage](#advanced-usage)
+ - [Additional Options](#additional-options)
+ - [Setting the endpoint](#setting-the-endpoint)
+ - [Configuring the Faraday Client](#configuring-the-faraday-client)
+ - [Using the Faraday Client](#using-the-faraday-client)
+ - [Overriding the Client](#overriding-the-client)
+- [Development and Testing](#development-and-testing)
+ - [Quickstart](#quickstart)
+ - [Source code](#source-code)
+ - [Requirements](#requirements)
+ - [Publishing](#publishing)
+ - [Automatic](#automatic)
+ - [Manual](#manual)
+- [GitHub Actions](#github-actions)
+ - [Secrets for Optional GitHub Actions](#secrets-for-optional-github-actions)
+- [Contributing](#contributing)
+- [License](#license)
+- [Warranty](#warranty)
+
+<!-- tocstop -->
+
## Installation
-Add this as a dependency to your project using [Bundler] with
+Add this as a dependency to your project using [Bundler] with:
```
$ bundle add seam
```
-[bundler]: https://bundler.io/
+[Bundler]: https://bundler.io/
+
+## Usage
+
+### Examples
+
+> [!NOTE]
+> These examples assume `SEAM_API_KEY` is set in your environment.
+
+#### List devices
+
+```ruby
+require "seam"
+
+seam = Seam.new
+devices = seam.devices.list
+```
+
+#### Unlock a door
+
+```ruby
+require "seam"
+
+seam = Seam.new
+lock = seam.locks.get(name: "Front Door")
+seam.locks.unlock_door(device_id: lock.device_id)
+```
+
+### Authentication Method
+
+The SDK supports API key and personal access token authentication mechanisms.
+Authentication may be configured by passing the corresponding options directly to the `Seam` constructor, or with the more ergonomic static factory methods.
+
+#### API Key
+
+An API key is scoped to a single workspace and should only be used on the server.
+Obtain one from the Seam Console.
+
+```ruby
+# Set the `SEAM_API_KEY` environment variable
+seam = Seam.new
+
+# Pass as a keyword argument to the constructor
+seam = Seam.new(api_key: "your-api-key")
+
+# Use the factory method
+seam = Seam.from_api_key("your-api-key")
+```
+
+#### Personal Access Token
+
+A Personal Access Token is scoped to a Seam Console user.
+Obtain one from the Seam Console.
+A workspace ID must be provided when using this method and all requests will be scoped to that workspace.
+
+```ruby
+# Pass as an option to the constructor
+seam = Seam.new(
+ personal_access_token: "your-personal-access-token",
+ workspace_id: "your-workspace-id"
+)
+
+# Use the factory method
+seam = Seam.from_personal_access_token(
+ "your-personal-access-token",
+ "your-workspace-id"
+)
+```
+
+### Action Attempts
+
+Some asynchronous operations, e.g., unlocking a door, return an
+[action attempt](https://docs.seam.co/latest/core-concepts/action-attempts).
+Seam tracks the progress of the requested operation and updates the action attempt
+when it succeeds or fails.
+
+To make working with action attempts more convenient for applications,
+this library provides the `wait_for_action_attempt` option and enables it by default.
+
+When the `wait_for_action_attempt` option is enabled, the SDK:
+
+- Polls the action attempt up to the `timeout`
+ at the `polling_interval` (both in seconds).
+- Resolves with a fresh copy of the successful action attempt.
+- Raises a `Seam::ActionAttemptFailedError` if the action attempt is unsuccessful.
+- Raises a `Seam::ActionAttemptTimeoutError` if the action attempt is still pending when the `timeout` is reached.
+- Both errors expose an `action_attempt` property.
+
+If you already have an action attempt ID
+and want to wait for it to resolve, simply use:
+
+```ruby
+seam.action_attempts.get(action_attempt_id: action_attempt_id)
+```
+
+Or, to get the current state of an action attempt by ID without waiting:
+
+```ruby
+seam.action_attempts.get(
+ action_attempt_id: action_attempt_id,
+ wait_for_action_attempt: false
+)
+```
+
+To disable this behavior, set the default option for the client:
+
+```ruby
+seam = Seam.new(
+ api_key: "your-api-key",
+ wait_for_action_attempt: false
+)
+
+seam.locks.unlock_door(device_id: device_id)
+```
+
+or the behavior may be configured per-request:
+
+```ruby
+seam.locks.unlock_door(
+ device_id: device_id,
+ wait_for_action_attempt: false
+)
+```
+
+The `polling_interval` and `timeout` may be configured for the client or per-request.
+For example:
+
+```ruby
+require "seam"
+
+seam = Seam.new("your-api-key")
+
+locks = seam.locks.list
+
+if locks.empty?
+ raise "No locks in this workspace"
+end
+
+lock = locks.first
+
+begin
+ seam.locks.unlock_door(
+ device_id: lock.device_id,
+ wait_for_action_attempt: {
+ timeout: 5.0,
+ polling_interval: 1.0
+ }
+ )
+
+ puts "Door unlocked"
+rescue Seam::ActionAttemptFailedError
+ puts "Could not unlock the door"
+rescue Seam::ActionAttemptTimeoutError
+ puts "Door took too long to unlock"
+end
+```
+
+### Interacting with Multiple Workspaces
+
+Some Seam API endpoints interact with multiple workspaces. The `Seam::Http::SeamMultiWorkspace` client is not bound to a specific workspace and may use those endpoints with a personal access token authentication method.
+
+A Personal Access Token is scoped to a Seam Console user. Obtain one from the Seam Console.
+
+```ruby
+# Pass as an option to the constructor
+seam = Seam::Http::SeamMultiWorkspace.new(personal_access_token: "your-personal-access-token")
+
+# Use the factory method
+seam = Seam::Http::SeamMultiWorkspace.from_personal_access_token("your-personal-access-token")
+
+# List workspaces authorized for this Personal Access Token
+workspaces = seam.workspaces.list
+```
+
+### Webhooks
+
+The Seam API implements webhooks using [Svix](https://www.svix.com).This SDK exports a thin wrapper `Seam::Webhook` around the svix package.
+Use it to parse and validate Seam webhook events.
+
+> [!TIP]
+> This example is for [Sinatra](https://sinatrarb.com/), see the [Svix docs for more examples in specific frameworks](https://docs.svix.com/receiving/verifying-payloads/how).
+
+```ruby
+require "sinatra"
+require "seam"
+
+webhook = Seam::Webhook.new(ENV["SEAM_WEBHOOK_SECRET"])
+
+post "/webhook" do
+ begin
+ headers = {
+ "svix-id" => request.env["HTTP_SVIX_ID"],
+ "svix-signature" => request.env["HTTP_SVIX_SIGNATURE"],
+ "svix-timestamp" => request.env["HTTP_SVIX_TIMESTAMP"]
+ }
+ data = webhook.verify(request.body.read, headers)
+ rescue Seam::WebhookVerificationError
+ halt 400, "Bad Request"
+ end
+
+ begin
+ store_event(data)
+ rescue
+ halt 500, "Internal Server Error"
+ end
+
+ 204
+end
+
+def store_event(data)
+ puts data
+end
+```
+
+### Advanced Usage
+
+#### Additional Options
+
+In addition to the various authentication options,
+the constructor takes some advanced options that affect behavior.
+
+```ruby
+seam = Seam.new(
+ api_key: "your-api-key",
+ endpoint: "https://example.com",
+ faraday_options: {},
+ faraday_retry_options: {}
+)
+```
+
+When using the static factory methods,
+these options may be passed in as keyword arguments.
+
+```ruby
+seam = Seam.from_api_key("some-api-key",
+ endpoint: "https://example.com",
+ faraday_options: {},
+ faraday_retry_options: {})
+```
+
+#### Setting the endpoint
+
+Some contexts may need to override the API endpoint,
+e.g., testing or proxy setups. This option corresponds to the [Faraday](https://lostisland.github.io/faraday/#/) `url` setting.
+
+Either pass the `endpoint` option, or set the `SEAM_ENDPOINT` environment variable.
+
+#### Configuring the Faraday Client
+
+The Faraday client and retry behavior may be configured with custom initiation options
+via [`faraday_option`][faraday_option] and [`faraday_retry_option`][faraday_retry_option].
+
+[faraday_option]: https://lostisland.github.io/faraday/#/customization/connection-options?id=connection-options
+[faraday_retry_option]: https://github.com/lostisland/faraday-retry
+
+#### Using the Faraday Client
+
+The Faraday client is exposed and may be used or configured directly:
+
+```ruby
+require "seam"
+require "faraday"
+
+class MyMiddleware < Faraday::Middleware
+ def on_complete(env)
+ puts env.response.inspect
+ end
+end
+
+seam = Seam.new
+
+seam.client.builder.use MyMiddleware
+
+devices = seam.client.get("/devices/list").body["devices"]
+```
+
+#### Overriding the Client
+
+A Faraday compatible client may be provided to create a `Seam` instance.
+This API is used internally and is not directly supported.
## Development and Testing
### Quickstart