Skip to content

Commit 574a629

Browse files
committed
feat: SeatLayer Ruby server SDK 0.1.0
Sixth server SDK. Same operations as the other five, in Ruby idiom: keyword arguments, predicate methods (sold_out?, mode_mismatch?), a single SeatLayer::Error ancestor so `rescue SeatLayer::Error` catches everything, and list_all returning a lazy Enumerator when no block is given — so .lazy.first(n) stops fetching instead of walking every page. No runtime dependencies: net/http, json and openssl from stdlib, no Faraday or HTTParty to conflict with whatever the host app already uses. 37 specs, RuboCop clean. RuboCop earned its keep here — it caught a Struct member named `method` in the test double, which silently overrides Struct#method and breaks anything reflecting on the object. Also prompted extracting the retry loop out of #request, which was doing too much to read in one pass. Verified by building the gem and installing it into a clean GEM_HOME, which is what proves the gemspec's file list is right.
0 parents  commit 574a629

20 files changed

Lines changed: 1650 additions & 0 deletions

‎.github/workflows/ci.yml‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
validate:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
ruby-version: ["3.0", "3.2", "3.4"]
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: ruby/setup-ruby@v1
17+
with:
18+
ruby-version: ${{ matrix.ruby-version }}
19+
bundler-cache: true
20+
- run: bundle exec rubocop
21+
- run: bundle exec rspec

‎.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/pkg/
2+
/tmp/
3+
/.bundle/
4+
Gemfile.lock
5+
*.gem
6+
.DS_Store

‎.rspec‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--require spec_helper
2+
--format documentation

‎.rubocop.yml‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
AllCops:
2+
TargetRubyVersion: 3.0
3+
NewCops: enable
4+
SuggestExtensions: false
5+
6+
Metrics/MethodLength:
7+
Max: 40
8+
Metrics/AbcSize:
9+
Max: 40
10+
Metrics/ClassLength:
11+
Max: 250
12+
Metrics/ParameterLists:
13+
Max: 8
14+
Metrics/CyclomaticComplexity:
15+
Max: 12
16+
Metrics/PerceivedComplexity:
17+
Max: 12
18+
Layout/LineLength:
19+
Max: 110
20+
Style/Documentation:
21+
Enabled: true
22+
23+
# `bundle gem` generates double-quoted strings, and the codebase is written that
24+
# way; the default single-quote rule would be pure churn.
25+
Style/StringLiterals:
26+
EnforcedStyle: double_quotes
27+
Style/StringLiteralsInInterpolation:
28+
EnforcedStyle: double_quotes
29+
30+
# Specs are allowed to be long and to describe behaviour in many examples.
31+
Metrics/BlockLength:
32+
Exclude:
33+
- "spec/**/*.rb"
34+
- "*.gemspec"

‎AGENTS.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Working in this repo
2+
3+
This is the SeatLayer **server** SDK. It talks to the API with a secret key and must never
4+
be usable from a browser.
5+
6+
## Rules
7+
8+
- **No runtime dependencies.** Standard library only: `net/http`, `json`, `openssl`. No Faraday,
9+
no HTTParty. Keep it that way —
10+
a server SDK that drags in a dependency tree is a supply-chain surface for every customer.
11+
- **The public surface is defined upstream** by `workers/api/src/publicApi.ts` in the app repo.
12+
A method here must map to an operation listed there. Do not wrap internal routes.
13+
- **Method names are the operationIds** from that manifest. Renaming one is a breaking change
14+
across every SeatLayer server SDK, not just this package.
15+
- **Ergonomics live here, not in the transport.** Things like "capabilities is required" and
16+
"expectedUpdatedAt is required" are deliberate divergences from the raw API; each one has a
17+
comment saying why.
18+
19+
## Checks
20+
21+
`bundle exec rubocop` and `bundle exec rspec`. CI runs both on Ruby 3.0, 3.2 and 3.4.

‎CHANGELOG.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Changelog
2+
3+
## 0.1.0 — unreleased
4+
5+
First release of the SeatLayer Ruby server SDK.
6+
7+
- `SeatLayer::Client` with secret-key auth, per-attempt timeouts, and an escape hatch.
8+
- Resources: `charts`, `events`, `inventory`, `sessions`, `webhooks`, `workspaces`.
9+
- Automatic `Idempotency-Key` on every mutation, reused across retries so a retried
10+
booking cannot become two bookings.
11+
- Retries on 429/408/5xx with exponential backoff and full jitter; honours `Retry-After`.
12+
4xx is never retried.
13+
- Typed errors: `AuthError` (with `mode_mismatch?`), `ConflictError` (with `conflicts`
14+
and `sold_out?`), `RateLimitError`, `ValidationError`, `NotFoundError`,
15+
`ConnectionError` — all under `SeatLayer::Error`.
16+
- `SeatLayer::Webhook.verify` — raw-body HMAC-SHA256 via `OpenSSL.secure_compare`.
17+
- `create_manage_session` requires explicit capabilities; the API's default grants
18+
`event:cancel`, which reverses paid bookings.
19+
- Constructor rejects a `pk_` key by name rather than failing as a 401 later.
20+
- `list_all` returns a lazy `Enumerator` when no block is given, so
21+
`.lazy.first(n)` does not walk every page.
22+
- No runtime dependencies — `net/http`, `json` and `openssl` from the standard library.
23+
24+
Requires Ruby 3.0 or newer.

‎Gemfile‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
source "https://rubygems.org"
4+
5+
gemspec
6+
7+
group :development, :test do
8+
gem "rspec", "~> 3.13"
9+
gem "rubocop", "~> 1.66"
10+
end

‎LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 SeatLayer
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)