seatlayer 0.3.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -1
- data/README.md +10 -8
- data/lib/seatlayer/performance_groups.rb +105 -0
- data/lib/seatlayer/resources.rb +32 -0
- data/lib/seatlayer/version.rb +1 -1
- data/lib/seatlayer.rb +5 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0ab55cb5752c5ddc06db43cfb1653248cebf2b0bd6c8b06be7b308653ca7f5cf
|
|
4
|
+
data.tar.gz: 44ec1f8c5e9f9da17e76c7e5913d1d1929ed4ca8be31d2fed6d24fc9d8521fe9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1252c05e9535563f4459383151d4dd8b8d9699766fbbce0fe453f21e020b310fe6d315f176aa071b3282af1f390a9cc1fd78b3d1efbdbe12d8f67f71249375f
|
|
7
|
+
data.tar.gz: 11f5318bd9b583d2b818446569d7f6b33285966a5dd7544045a03e2dad82a3325c685b51ae290a754a60182c067122eb8bb0999c03b0fe3403919eb21cfd1178
|
data/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.5.0 — 2026-08-21
|
|
6
|
+
|
|
7
|
+
- Added `performance_groups`, the trusted server resource for fixed two-to-eight
|
|
8
|
+
performance runs. It creates and activates groups, mints one-time browser
|
|
9
|
+
access, retrieves authoritative group holds, and confirms bookings with
|
|
10
|
+
stable action and order references. Browser-only group routes remain outside
|
|
11
|
+
this secret-key SDK.
|
|
12
|
+
|
|
13
|
+
- Added `templates.instantiate_template` and the ticket-release lifecycle on
|
|
14
|
+
`events` (`list_ticket_releases`, `update_ticket_releases`, and
|
|
15
|
+
`close_ticket_release`). Template instantiation sends `{}` when no overrides
|
|
16
|
+
are supplied, URI-escapes identifiers, and uses exact-response replay;
|
|
17
|
+
ticket-release writes remain single-attempt.
|
|
18
|
+
|
|
5
19
|
- **Security/reliability:** Mutations now default to a single attempt. Automatic header-replay
|
|
6
|
-
retries are limited to chart create/copy, event create, and workspace create, preventing
|
|
20
|
+
retries are limited to chart create/copy, template instantiation, event create, and workspace create, preventing
|
|
7
21
|
transient failures from duplicating holds or best-available results and from issuing extra
|
|
8
22
|
show-once credentials.
|
|
9
23
|
- Aligned event, inventory, webhook, manage-session, and Designer requests with the generated
|
data/README.md
CHANGED
|
@@ -30,8 +30,8 @@ require "seatlayer"
|
|
|
30
30
|
|
|
31
31
|
client = SeatLayer::Client.new(ENV.fetch("SEATLAYER_SECRET_KEY"))
|
|
32
32
|
|
|
33
|
-
# 1. Provision a venue for a new organiser from
|
|
34
|
-
chart = client.
|
|
33
|
+
# 1. Provision a venue for a new organiser from a public template.
|
|
34
|
+
chart = client.templates.instantiate_template("arena-standard")["meta"]
|
|
35
35
|
client.charts.publish(chart["id"])
|
|
36
36
|
|
|
37
37
|
# 2. Create an event on it.
|
|
@@ -252,11 +252,12 @@ error carries `status`, `code`, `body` and `request_id` — quote the request id
|
|
|
252
252
|
## Reliability
|
|
253
253
|
|
|
254
254
|
**Retries.** Reads (`GET`/`HEAD`) retry 429, 408 and 5xx with exponential backoff and full jitter;
|
|
255
|
-
`Retry-After` wins when the server sends it. Automatic mutation retries are limited to the
|
|
256
|
-
operations backed by exact response replay: `charts.create`, `charts.copy`,
|
|
257
|
-
`workspaces.create`. Other 4xx responses
|
|
255
|
+
`Retry-After` wins when the server sends it. Automatic mutation retries are limited to the five
|
|
256
|
+
operations backed by exact response replay: `charts.create`, `charts.copy`,
|
|
257
|
+
`templates.instantiate_template`, `events.create`, and `workspaces.create`. Other 4xx responses
|
|
258
|
+
are never retried.
|
|
258
259
|
|
|
259
|
-
**Idempotency.** Those
|
|
260
|
+
**Idempotency.** Those five replay-backed operations carry an `Idempotency-Key`, generated when you
|
|
260
261
|
do not supply one and reused across attempts. Other mutations are single-attempt and receive no
|
|
261
262
|
automatic key. A caller-supplied key is forwarded but does not enable retries. This includes
|
|
262
263
|
inventory holds and bookings, show-once credential or secret creation, unsupported operations, and
|
|
@@ -289,7 +290,8 @@ client.request("POST", "/v1/events/ev_1/some-new-route", body: { "qty" => 2 })
|
|
|
289
290
|
| Resource | Methods |
|
|
290
291
|
| --- | --- |
|
|
291
292
|
| `charts` | `list` `list_all` `create` `retrieve` `update` `delete` `copy` `archive` `unarchive` `publish` |
|
|
292
|
-
| `
|
|
293
|
+
| `templates` | `instantiate_template` |
|
|
294
|
+
| `events` | `list` `list_all` `create` `retrieve` `update` `delete` `update_poster` `delete_poster` `update_chart` `close` `reopen` `archive` `retrieve_hold_ttl` `update_hold_ttl` `list_ticket_releases` `update_ticket_releases` `close_ticket_release` `retrieve_report` `retrieve_log` |
|
|
293
295
|
| `inventory` | `hold` `hold_best_available` `book_best_available` `extend_hold` `retrieve_hold` `release` `book` `box_office_book` `unbook` `list_bookings` `retrieve_booking` `block` `unblock` `unblock_all` `retrieve_availability` `update_availability` |
|
|
294
296
|
| `channels` | `list_channels` `create_channel` `update_channel` `update_assignments` `list_allocation` `retrieve_access_preview` `retrieve_report` `pause` `unpause` `archive` `create_buyer_access_session` `list_buyer_access_sessions` `revoke_buyer_access_session` `create_access_link` `list_access_links` `rotate_access_link` `revoke_access_link` |
|
|
295
297
|
| `sessions` | `create_manage_session` `revoke_manage_session` `create_designer_session` `revoke_designer_session` |
|
|
@@ -337,7 +339,7 @@ the public manifest, not just from the wrapper.
|
|
|
337
339
|
| Node.js (server) | [`@seatlayer/server`](https://www.npmjs.com/package/@seatlayer/server) |
|
|
338
340
|
| Python (server) | [`seatlayer`](https://pypi.org/project/seatlayer/) |
|
|
339
341
|
| PHP (server) | [`seatlayer/seatlayer-php`](https://packagist.org/packages/seatlayer/seatlayer-php) |
|
|
340
|
-
| Java (server) | [`io.seatlayer:seatlayer-java`](https://central.sonatype.com/artifact/io.seatlayer/seatlayer-java/0.
|
|
342
|
+
| Java (server) | [`io.seatlayer:seatlayer-java`](https://central.sonatype.com/artifact/io.seatlayer/seatlayer-java/0.3.0) |
|
|
341
343
|
| Go (server) | [`github.com/seatlayer/seatlayer-go`](https://pkg.go.dev/github.com/seatlayer/seatlayer-go) |
|
|
342
344
|
| .NET (server) | [`SeatLayer`](https://www.nuget.org/packages/SeatLayer) |
|
|
343
345
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SeatLayer
|
|
4
|
+
# Fixed multi-performance runs. This is a secret-key surface: mint the
|
|
5
|
+
# browser token here, then give that token (never this client) to the
|
|
6
|
+
# PerformanceGroupPicker in the browser SDK.
|
|
7
|
+
class PerformanceGroups < Resource
|
|
8
|
+
# One page of fixed runs.
|
|
9
|
+
def list(workspace_id: nil, external_ref: nil, state: nil, limit: nil, cursor: nil)
|
|
10
|
+
@client.get("/v1/performance-groups", compact({ "workspaceId" => workspace_id,
|
|
11
|
+
"externalRef" => external_ref,
|
|
12
|
+
"state" => state, "limit" => limit,
|
|
13
|
+
"cursor" => cursor }))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Create a draft from two to eight compatible assigned-seat events. The
|
|
17
|
+
# server validates compatibility and exactly replays a request with the
|
|
18
|
+
# same idempotency key.
|
|
19
|
+
def create(name:, event_keys:, external_ref: UNSET, idempotency_key: nil)
|
|
20
|
+
body = { "name" => name, "eventKeys" => event_keys }
|
|
21
|
+
body.merge!(supplied({ "externalRef" => external_ref }))
|
|
22
|
+
@client.post("/v1/performance-groups", body, idempotency_key: idempotency_key,
|
|
23
|
+
retry_policy: :header_replay)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def retrieve(performance_group_key)
|
|
27
|
+
@client.get(path(performance_group_key))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Only a draft can be deleted. Activated runs retain their audit identity.
|
|
31
|
+
def delete(performance_group_key)
|
|
32
|
+
@client.delete(path(performance_group_key))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Starts lifecycle coordination. When its response contains a non-terminal
|
|
36
|
+
# lifecycle operation, poll +retrieve_lifecycle+ until it completes.
|
|
37
|
+
def activate(performance_group_key, expected_revision:)
|
|
38
|
+
@client.post(path(performance_group_key, "/activate"),
|
|
39
|
+
{ "expectedRevision" => expected_revision })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Stops new group sales. Poll +retrieve_lifecycle+ while the close remains pending.
|
|
43
|
+
def close(performance_group_key, expected_revision:)
|
|
44
|
+
@client.post(path(performance_group_key, "/close"),
|
|
45
|
+
{ "expectedRevision" => expected_revision })
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def retrieve_lifecycle(performance_group_key, operation_id)
|
|
49
|
+
@client.get(path(performance_group_key, "/lifecycle/#{encode(operation_id)}"))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Reveals a one-time, origin-bound browser bearer. It intentionally remains
|
|
53
|
+
# single-attempt: a retry could create a token whose only reveal is lost.
|
|
54
|
+
def create_buyer_access_session(performance_group_key, allowed_origin:, include_public:,
|
|
55
|
+
channel_ids_by_event: nil, expires_in_seconds: nil,
|
|
56
|
+
max_quantity: UNSET, buyer_ref: UNSET, partner_ref: UNSET)
|
|
57
|
+
body = compact({ "allowedOrigin" => allowed_origin, "includePublic" => include_public,
|
|
58
|
+
"channelIdsByEvent" => channel_ids_by_event,
|
|
59
|
+
"expiresInSeconds" => expires_in_seconds })
|
|
60
|
+
body.merge!(supplied({ "maxQuantity" => max_quantity, "buyerRef" => buyer_ref,
|
|
61
|
+
"partnerRef" => partner_ref }))
|
|
62
|
+
@client.post(path(performance_group_key, "/buyer-access-sessions"), body)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Token records only: the bearer value is never returned again.
|
|
66
|
+
def list_buyer_access_sessions(performance_group_key, limit: nil)
|
|
67
|
+
@client.get(path(performance_group_key, "/buyer-access-sessions"), { "limit" => limit })
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def revoke_buyer_access_session(performance_group_key, session_id)
|
|
71
|
+
@client.delete(path(performance_group_key, "/buyer-access-sessions/#{encode(session_id)}"))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Read the trusted server projection before charging; do not price from
|
|
75
|
+
# client input or the picker state.
|
|
76
|
+
def retrieve_hold(performance_group_key, operation_id)
|
|
77
|
+
@client.get(path(performance_group_key, "/holds/#{encode(operation_id)}"))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Confirm external payment for a committed hold. Keep both identifiers
|
|
81
|
+
# stable, and poll +retrieve_booking+ if the response is +book_pending+.
|
|
82
|
+
def book_hold(performance_group_key, operation_id, book_action_id:, booking_ref:)
|
|
83
|
+
@client.post(path(performance_group_key, "/holds/#{encode(operation_id)}/book"),
|
|
84
|
+
{ "bookActionId" => book_action_id,
|
|
85
|
+
"bookingRef" => normalise_booking_ref(booking_ref) })
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def retrieve_booking(performance_group_key, action_id)
|
|
89
|
+
@client.get(path(performance_group_key, "/bookings/#{encode(action_id)}"))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def path(performance_group_key, suffix = "")
|
|
95
|
+
"/v1/performance-groups/#{encode(performance_group_key)}#{suffix}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def normalise_booking_ref(booking_ref)
|
|
99
|
+
value = booking_ref&.strip
|
|
100
|
+
return value unless value.nil? || value.empty?
|
|
101
|
+
|
|
102
|
+
raise ArgumentError, "booking_ref is required and must be a non-empty stable reference"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
data/lib/seatlayer/resources.rb
CHANGED
|
@@ -129,6 +129,23 @@ module SeatLayer
|
|
|
129
129
|
end
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
+
# Published SeatLayer catalogue templates.
|
|
133
|
+
#
|
|
134
|
+
# Instantiation creates an independent draft chart. Publish that returned
|
|
135
|
+
# chart before creating an event from it.
|
|
136
|
+
class Templates < Resource
|
|
137
|
+
# Instantiate a public template into a new draft chart.
|
|
138
|
+
#
|
|
139
|
+
# +fields+ intentionally defaults to an empty Hash: the API requires a JSON
|
|
140
|
+
# object even when there are no overrides, and JSON.generate({}) is `{}`.
|
|
141
|
+
def instantiate_template(template_id, fields: {}, idempotency_key: nil)
|
|
142
|
+
@client.post(
|
|
143
|
+
"/v1/templates/#{encode(template_id)}/instantiate", fields,
|
|
144
|
+
idempotency_key: idempotency_key, retry_policy: :header_replay
|
|
145
|
+
)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
132
149
|
# Event lifecycle, metadata and reports.
|
|
133
150
|
class Events < Resource
|
|
134
151
|
# One page of events.
|
|
@@ -225,6 +242,21 @@ module SeatLayer
|
|
|
225
242
|
@client.post("/v1/events/#{encode(event_key)}/hold-ttl", { "holdTtlMs" => hold_ttl_ms })
|
|
226
243
|
end
|
|
227
244
|
|
|
245
|
+
def list_ticket_releases(event_key)
|
|
246
|
+
@client.get("/v1/events/#{encode(event_key)}/releases")
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Replace every ticket release for an event. This stays single-attempt: the
|
|
250
|
+
# route does not promise exact idempotent-response replay.
|
|
251
|
+
def update_ticket_releases(event_key, releases:)
|
|
252
|
+
@client.put("/v1/events/#{encode(event_key)}/releases", { "releases" => releases })
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Close one release while preserving its audit provenance.
|
|
256
|
+
def close_ticket_release(event_key, release_id)
|
|
257
|
+
@client.post("/v1/events/#{encode(event_key)}/releases/#{encode(release_id)}/close")
|
|
258
|
+
end
|
|
259
|
+
|
|
228
260
|
def retrieve_report(event_key)
|
|
229
261
|
@client.get("/v1/events/#{encode(event_key)}/report")
|
|
230
262
|
end
|
data/lib/seatlayer/version.rb
CHANGED
data/lib/seatlayer.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative "seatlayer/http_client"
|
|
|
6
6
|
require_relative "seatlayer/resources"
|
|
7
7
|
require_relative "seatlayer/inventory"
|
|
8
8
|
require_relative "seatlayer/channels"
|
|
9
|
+
require_relative "seatlayer/performance_groups"
|
|
9
10
|
require_relative "seatlayer/webhook"
|
|
10
11
|
|
|
11
12
|
# Official Ruby server SDK for the SeatLayer reserved-seating API.
|
|
@@ -19,7 +20,8 @@ require_relative "seatlayer/webhook"
|
|
|
19
20
|
module SeatLayer
|
|
20
21
|
# The SeatLayer client.
|
|
21
22
|
class Client
|
|
22
|
-
attr_reader :charts, :events, :inventory, :channels, :
|
|
23
|
+
attr_reader :charts, :events, :inventory, :channels, :performance_groups, :sessions,
|
|
24
|
+
:webhooks, :workspaces, :templates
|
|
23
25
|
|
|
24
26
|
def initialize(secret_key, base_url: HTTPClient::DEFAULT_BASE_URL,
|
|
25
27
|
max_retries: HTTPClient::DEFAULT_MAX_RETRIES,
|
|
@@ -31,7 +33,9 @@ module SeatLayer
|
|
|
31
33
|
@events = Events.new(@http)
|
|
32
34
|
@inventory = Inventory.new(@http)
|
|
33
35
|
@channels = Channels.new(@http)
|
|
36
|
+
@performance_groups = PerformanceGroups.new(@http)
|
|
34
37
|
@sessions = Sessions.new(@http)
|
|
38
|
+
@templates = Templates.new(@http)
|
|
35
39
|
@webhooks = Webhooks.new(@http)
|
|
36
40
|
@workspaces = Workspaces.new(@http)
|
|
37
41
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: seatlayer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- SeatLayer
|
|
@@ -25,6 +25,7 @@ files:
|
|
|
25
25
|
- lib/seatlayer/errors.rb
|
|
26
26
|
- lib/seatlayer/http_client.rb
|
|
27
27
|
- lib/seatlayer/inventory.rb
|
|
28
|
+
- lib/seatlayer/performance_groups.rb
|
|
28
29
|
- lib/seatlayer/resources.rb
|
|
29
30
|
- lib/seatlayer/version.rb
|
|
30
31
|
- lib/seatlayer/webhook.rb
|