aho-sdk 0.1.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 +7 -0
- data/CHANGELOG.md +18 -0
- data/LICENSE.txt +18 -0
- data/README.md +278 -0
- data/lib/aho_sdk/account.rb +226 -0
- data/lib/aho_sdk/cursor_page.rb +87 -0
- data/lib/aho_sdk/holder.rb +102 -0
- data/lib/aho_sdk/http_client.rb +420 -0
- data/lib/aho_sdk/issuer.rb +502 -0
- data/lib/aho_sdk/page.rb +82 -0
- data/lib/aho_sdk/public.rb +60 -0
- data/lib/aho_sdk/schemas.rb +85 -0
- data/lib/aho_sdk/system.rb +46 -0
- data/lib/aho_sdk/verifier.rb +152 -0
- data/lib/aho_sdk/version.rb +7 -0
- data/lib/aho_sdk.rb +88 -0
- metadata +74 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 72d0e9a4889740cb021e3df8a786d25ac7e0005ed8161d77c38cb8de84e8d92a
|
|
4
|
+
data.tar.gz: bce01a4cdb564cca550f17956aead22aa2e56c3e7a862b1ffd5649fbbb3113b0
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ab85b572852b0e5ae5247a489685332cd52be3cb2a444cc9b41f9e5c195d678e71aeee995109e074adda5db0f1a383db302ed73ba24e3f1c972a0b6be1bd7c78
|
|
7
|
+
data.tar.gz: 4588cfed2ef06d2edc5c2da651694e70439f4613a19b37fd5690e1f05704102a109b9fc4560f0593d52582289b9b2c88e73b5538b7f492ead25824ecc779cf77
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-03-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release
|
|
13
|
+
- Issuer client for credential issuance
|
|
14
|
+
- Holder client for wallet management
|
|
15
|
+
- Verifier client for presentation verification
|
|
16
|
+
- Account client for account management
|
|
17
|
+
- Pagination support
|
|
18
|
+
- Comprehensive error handling
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# AhoSdk Ruby SDK
|
|
2
|
+
|
|
3
|
+
Official Ruby SDK for the [Aho](https://aho.com) Verifiable Credentials API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'aho-sdk'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install directly:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
gem install aho-sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require 'aho-sdk'
|
|
23
|
+
|
|
24
|
+
# Initialize the Issuer client
|
|
25
|
+
issuer = AhoSdk::Issuer.new(api_key: ENV['AHO_ISSUER_API_KEY'])
|
|
26
|
+
|
|
27
|
+
# Issue a credential
|
|
28
|
+
credential = issuer.credentials.create(
|
|
29
|
+
schema_uuid: 'your-schema-uuid',
|
|
30
|
+
subject_identifier: 'user@example.com',
|
|
31
|
+
claims: {
|
|
32
|
+
name: 'Jane Doe',
|
|
33
|
+
role: 'Engineer'
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
puts credential['uuid']
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Clients
|
|
41
|
+
|
|
42
|
+
The SDK provides the following clients:
|
|
43
|
+
|
|
44
|
+
| Client | Purpose | API Key Type |
|
|
45
|
+
|--------|---------|--------------|
|
|
46
|
+
| `AhoSdk::Account` | Manage account settings, domains, and API keys | Account API Key |
|
|
47
|
+
| `AhoSdk::System` | System health and status endpoints | System API Key |
|
|
48
|
+
| `AhoSdk::Holder` | Manage holder credentials and presentations | Holder API Key |
|
|
49
|
+
| `AhoSdk::Verifier` | Create presentation requests and verify credentials | Verifier API Key |
|
|
50
|
+
| `AhoSdk::Issuer` | Issue and manage verifiable credentials | Issuer API Key |
|
|
51
|
+
| `AhoSdk::Schemas` | Browse and retrieve credential schemas | Schemas API Key |
|
|
52
|
+
| `AhoSdk::Public` | Public endpoints (no authentication required) | None (public) |
|
|
53
|
+
|
|
54
|
+
## Usage Examples
|
|
55
|
+
|
|
56
|
+
### Issuing Credentials
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
issuer = AhoSdk::Issuer.new(api_key: ENV['AHO_ISSUER_API_KEY'])
|
|
60
|
+
|
|
61
|
+
# List all schemas
|
|
62
|
+
schemas = issuer.schemas.list
|
|
63
|
+
schemas.data.each { |s| puts s['name'] }
|
|
64
|
+
|
|
65
|
+
# Create a schema
|
|
66
|
+
schema = issuer.schemas.create(
|
|
67
|
+
name: 'EmployeeBadge',
|
|
68
|
+
claims: [
|
|
69
|
+
{ name: 'employee_id', type: 'string', required: true },
|
|
70
|
+
{ name: 'department', type: 'string', required: true },
|
|
71
|
+
{ name: 'hire_date', type: 'date', required: false }
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Issue a credential
|
|
76
|
+
credential = issuer.credentials.create(
|
|
77
|
+
schema_uuid: schema['uuid'],
|
|
78
|
+
subject_identifier: 'jane.doe@company.com',
|
|
79
|
+
claims: {
|
|
80
|
+
employee_id: 'EMP-12345',
|
|
81
|
+
department: 'Engineering',
|
|
82
|
+
hire_date: '2024-01-15'
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Revoke a credential
|
|
87
|
+
issuer.credentials.revoke(uuid: credential['uuid'], reason: 'Employee departed')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Verifying Credentials
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
verifier = AhoSdk::Verifier.new(api_key: ENV['AHO_VERIFIER_API_KEY'])
|
|
94
|
+
|
|
95
|
+
# Create a presentation request
|
|
96
|
+
request = verifier.requests.create(
|
|
97
|
+
name: 'Employment Verification',
|
|
98
|
+
query_format: 'dcql',
|
|
99
|
+
credentials: [
|
|
100
|
+
{
|
|
101
|
+
id: 'employee_badge',
|
|
102
|
+
format: 'vc+sd-jwt',
|
|
103
|
+
claims: [
|
|
104
|
+
{ path: ['employee_id'] },
|
|
105
|
+
{ path: ['department'] }
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Get the QR code for the request (supports :png, :svg formats)
|
|
112
|
+
qr = verifier.requests.qr_code(uuid: request['uuid'], output_format: :svg)
|
|
113
|
+
|
|
114
|
+
# List responses to the request
|
|
115
|
+
responses = verifier.responses.list(request_uuid: request['uuid'])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Managing Holder Credentials
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
holder = AhoSdk::Holder.new(api_key: ENV['AHO_HOLDER_API_KEY'])
|
|
122
|
+
|
|
123
|
+
# List credentials
|
|
124
|
+
credentials = holder.credentials.list(status: 'active')
|
|
125
|
+
|
|
126
|
+
# Create a presentation (selective disclosure)
|
|
127
|
+
presentation = holder.presentations.create(
|
|
128
|
+
credential_uuid: 'credential-uuid',
|
|
129
|
+
disclosed_claims: ['name', 'department']
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Account Management
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
account = AhoSdk::Account.new(api_key: ENV['AHO_API_KEY'])
|
|
137
|
+
|
|
138
|
+
# Manage domains
|
|
139
|
+
domains = account.domains.list
|
|
140
|
+
account.domains.verify(id: domain['id'])
|
|
141
|
+
|
|
142
|
+
# Manage signing keys
|
|
143
|
+
keys = account.signing_keys.list
|
|
144
|
+
account.signing_keys.rotate(id: key['id'])
|
|
145
|
+
|
|
146
|
+
# Configure webhooks
|
|
147
|
+
account.webhooks.create(
|
|
148
|
+
url: 'https://your-app.com/webhooks/aho',
|
|
149
|
+
events: ['credential.issued', 'credential.revoked']
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Pagination
|
|
154
|
+
|
|
155
|
+
List methods return `Page` objects with built-in iteration:
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
# Iterate through all pages automatically
|
|
159
|
+
issuer.credentials.list.each do |credential|
|
|
160
|
+
puts credential['uuid']
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Or handle pages manually
|
|
164
|
+
page = issuer.credentials.list(per_page: 50)
|
|
165
|
+
while page
|
|
166
|
+
page.data.each { |c| puts c['uuid'] }
|
|
167
|
+
page = page.next_page
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Collect all items
|
|
171
|
+
all_credentials = issuer.credentials.list.to_a
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## File Uploads
|
|
175
|
+
|
|
176
|
+
For endpoints that accept file uploads:
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
# Upload a file
|
|
180
|
+
issuer.media.upload(
|
|
181
|
+
file: File.open('document.pdf'),
|
|
182
|
+
metadata: { description: 'Employee contract' }
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# The SDK auto-detects MIME types from file extensions
|
|
186
|
+
# You can also pass a path string:
|
|
187
|
+
issuer.media.upload(file: '/path/to/document.pdf')
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Binary Responses
|
|
191
|
+
|
|
192
|
+
Some endpoints return binary data (images, PDFs):
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
# Get QR code as PNG
|
|
196
|
+
png_data = verifier.requests.qr_code(uuid: '...', output_format: :png)
|
|
197
|
+
File.binwrite('qr.png', png_data)
|
|
198
|
+
|
|
199
|
+
# Get QR code as SVG
|
|
200
|
+
svg_data = verifier.requests.qr_code(uuid: '...', output_format: :svg)
|
|
201
|
+
File.write('qr.svg', svg_data)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Error Handling
|
|
205
|
+
|
|
206
|
+
```ruby
|
|
207
|
+
begin
|
|
208
|
+
issuer.credentials.create(invalid_params)
|
|
209
|
+
rescue AhoSdk::ValidationError => e
|
|
210
|
+
# 422 - Validation failed
|
|
211
|
+
e.field_errors.each do |error|
|
|
212
|
+
puts "#{error['field']}: #{error['hint']}"
|
|
213
|
+
end
|
|
214
|
+
rescue AhoSdk::AuthenticationError => e
|
|
215
|
+
# 401 - Invalid API key
|
|
216
|
+
puts "Check your API key"
|
|
217
|
+
rescue AhoSdk::NotFoundError => e
|
|
218
|
+
# 404 - Resource not found
|
|
219
|
+
puts "Resource not found: #{e.message}"
|
|
220
|
+
rescue AhoSdk::RateLimitError => e
|
|
221
|
+
# 429 - Rate limited (SDK auto-retries with exponential backoff)
|
|
222
|
+
puts "Retry after #{e.retry_after} seconds"
|
|
223
|
+
rescue AhoSdk::ApiError => e
|
|
224
|
+
# Other API errors
|
|
225
|
+
puts "Error #{e.status_code}: #{e.message}"
|
|
226
|
+
puts "Request ID: #{e.request_id}"
|
|
227
|
+
end
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Error Classes
|
|
231
|
+
|
|
232
|
+
| Error Class | HTTP Status | Description |
|
|
233
|
+
|-------------|-------------|-------------|
|
|
234
|
+
| `AuthenticationError` | 401 | Invalid or missing API key |
|
|
235
|
+
| `ForbiddenError` | 403 | Insufficient permissions |
|
|
236
|
+
| `NotFoundError` | 404 | Resource not found |
|
|
237
|
+
| `ConflictError` | 409 | Resource conflict |
|
|
238
|
+
| `ValidationError` | 422 | Request validation failed |
|
|
239
|
+
| `RateLimitError` | 429 | Rate limit exceeded |
|
|
240
|
+
| `ServerError` | 5xx | Server-side error |
|
|
241
|
+
| `NetworkError` | - | Connection/timeout error |
|
|
242
|
+
| `ApiError` | * | Base class for all API errors |
|
|
243
|
+
|
|
244
|
+
## Rate Limiting
|
|
245
|
+
|
|
246
|
+
The SDK automatically handles rate limits with exponential backoff:
|
|
247
|
+
|
|
248
|
+
- **Idempotent methods** (GET, DELETE, PUT): Auto-retry up to 3 times
|
|
249
|
+
- **Non-idempotent methods** (POST, PATCH): Only retry with idempotency key
|
|
250
|
+
|
|
251
|
+
```ruby
|
|
252
|
+
# Use idempotency keys for safe retries on POST/PATCH
|
|
253
|
+
issuer.credentials.create(
|
|
254
|
+
schema_uuid: '...',
|
|
255
|
+
claims: { ... },
|
|
256
|
+
idempotency_key: 'unique-request-id'
|
|
257
|
+
)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Configuration
|
|
261
|
+
|
|
262
|
+
```ruby
|
|
263
|
+
# Custom configuration
|
|
264
|
+
issuer = AhoSdk::Issuer.new(
|
|
265
|
+
api_key: ENV['AHO_ISSUER_API_KEY'],
|
|
266
|
+
base_url: 'https://api.aho.com', # Custom base URL
|
|
267
|
+
timeout: 60, # Request timeout in seconds
|
|
268
|
+
logger: Logger.new(STDOUT) # Enable debug logging
|
|
269
|
+
)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Requirements
|
|
273
|
+
|
|
274
|
+
- Ruby 3.1+
|
|
275
|
+
|
|
276
|
+
## License
|
|
277
|
+
|
|
278
|
+
MIT
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Auto-generated by bin/generate_sdks.rb - DO NOT EDIT
|
|
4
|
+
|
|
5
|
+
require_relative "http_client"
|
|
6
|
+
require_relative "page"
|
|
7
|
+
require_relative "cursor_page"
|
|
8
|
+
|
|
9
|
+
module AhoSdk
|
|
10
|
+
# Manage account settings, domains, and API keys
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# client = AhoSdk::Account.new(api_key: ENV["AHO_ACCOUNT_API_KEY"])
|
|
14
|
+
# client.api_keys.list
|
|
15
|
+
# client.domains.list
|
|
16
|
+
# client.signing_keys.list
|
|
17
|
+
# client.webhooks.list
|
|
18
|
+
#
|
|
19
|
+
class Account
|
|
20
|
+
# @param api_key [String] API key for authentication
|
|
21
|
+
# @param base_url [String] Base URL (default: https://aho.com)
|
|
22
|
+
# @param timeout [Integer] Request timeout in seconds (default: 30)
|
|
23
|
+
# @param logger [Logger] Optional logger for debugging
|
|
24
|
+
def initialize(api_key:, base_url: "https://aho.com", timeout: 30, logger: nil)
|
|
25
|
+
@client = HttpClient.new(api_key: api_key, base_url: base_url, timeout: timeout, logger: logger)
|
|
26
|
+
@api_keys = ApiKeysResource.new(@client)
|
|
27
|
+
@domains = DomainsResource.new(@client)
|
|
28
|
+
@signing_keys = SigningKeysResource.new(@client)
|
|
29
|
+
@webhooks = WebhooksResource.new(@client)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [ApiKeysResource]
|
|
33
|
+
attr_reader :api_keys
|
|
34
|
+
# @return [DomainsResource]
|
|
35
|
+
attr_reader :domains
|
|
36
|
+
# @return [SigningKeysResource]
|
|
37
|
+
attr_reader :signing_keys
|
|
38
|
+
# @return [WebhooksResource]
|
|
39
|
+
attr_reader :webhooks
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Api_keys resource operations
|
|
43
|
+
# @api private
|
|
44
|
+
class ApiKeysResource
|
|
45
|
+
# @api private
|
|
46
|
+
def initialize(client)
|
|
47
|
+
@client = client
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# List API keys
|
|
51
|
+
#
|
|
52
|
+
# @return [Hash]
|
|
53
|
+
def list
|
|
54
|
+
@client.get("/api/v1/account/api_keys")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Create/regenerate API key
|
|
58
|
+
#
|
|
59
|
+
# @return [Hash]
|
|
60
|
+
def create(body: nil, idempotency_key: nil)
|
|
61
|
+
@client.post("/api/v1/account/api_keys", body: body, idempotency_key: idempotency_key)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Revoke API key
|
|
65
|
+
#
|
|
66
|
+
# @return [Hash]
|
|
67
|
+
def delete(id:)
|
|
68
|
+
@client.delete("/api/v1/account/api_keys/#{id}")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Domains resource operations
|
|
73
|
+
# @api private
|
|
74
|
+
class DomainsResource
|
|
75
|
+
# @api private
|
|
76
|
+
def initialize(client)
|
|
77
|
+
@client = client
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Register a domain
|
|
81
|
+
#
|
|
82
|
+
# @return [Hash]
|
|
83
|
+
def create(body: nil, idempotency_key: nil)
|
|
84
|
+
@client.post("/api/v1/account/domains", body: body, idempotency_key: idempotency_key)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# List domains
|
|
88
|
+
#
|
|
89
|
+
# @return [Hash]
|
|
90
|
+
def list(txt_status: nil, fully_verified: nil, primary: nil, page: nil, per_page: nil)
|
|
91
|
+
fetch_page = ->(p) {
|
|
92
|
+
response = @client.get("/api/v1/account/domains", params: { txt_status: txt_status, fully_verified: fully_verified, primary: primary, page: p, per_page: per_page })
|
|
93
|
+
Page.new(data: response[:data], meta: response[:meta], fetch_next: fetch_page)
|
|
94
|
+
}
|
|
95
|
+
fetch_page.call(page)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Get domain details
|
|
99
|
+
#
|
|
100
|
+
# @return [Hash]
|
|
101
|
+
def get(id:)
|
|
102
|
+
@client.get("/api/v1/account/domains/#{id}")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Delete a domain
|
|
106
|
+
#
|
|
107
|
+
# @return [Hash]
|
|
108
|
+
def delete(id:)
|
|
109
|
+
@client.delete("/api/v1/account/domains/#{id}")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Verify domain
|
|
113
|
+
#
|
|
114
|
+
# @return [Hash]
|
|
115
|
+
def verify(id:, idempotency_key: nil)
|
|
116
|
+
@client.post("/api/v1/account/domains/#{id}/verify", idempotency_key: idempotency_key)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Signing_keys resource operations
|
|
121
|
+
# @api private
|
|
122
|
+
class SigningKeysResource
|
|
123
|
+
# @api private
|
|
124
|
+
def initialize(client)
|
|
125
|
+
@client = client
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Generate a signing key
|
|
129
|
+
#
|
|
130
|
+
# @return [Hash]
|
|
131
|
+
def create(body: nil, idempotency_key: nil)
|
|
132
|
+
@client.post("/api/v1/account/signing_keys", body: body, idempotency_key: idempotency_key)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# List signing keys
|
|
136
|
+
#
|
|
137
|
+
# @return [Hash]
|
|
138
|
+
def list(status: nil, algorithm: nil, usable: nil, page: nil, per_page: nil)
|
|
139
|
+
fetch_page = ->(p) {
|
|
140
|
+
response = @client.get("/api/v1/account/signing_keys", params: { status: status, algorithm: algorithm, usable: usable, page: p, per_page: per_page })
|
|
141
|
+
Page.new(data: response[:data], meta: response[:meta], fetch_next: fetch_page)
|
|
142
|
+
}
|
|
143
|
+
fetch_page.call(page)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Get signing key details
|
|
147
|
+
#
|
|
148
|
+
# @return [Hash]
|
|
149
|
+
def get(id:)
|
|
150
|
+
@client.get("/api/v1/account/signing_keys/#{id}")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Rotate a signing key
|
|
154
|
+
#
|
|
155
|
+
# @return [Hash]
|
|
156
|
+
def rotate(id:, body: nil, idempotency_key: nil)
|
|
157
|
+
@client.post("/api/v1/account/signing_keys/#{id}/rotate", body: body, idempotency_key: idempotency_key)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Revoke a signing key
|
|
161
|
+
#
|
|
162
|
+
# @return [Hash]
|
|
163
|
+
def revoke(id:, idempotency_key: nil)
|
|
164
|
+
@client.post("/api/v1/account/signing_keys/#{id}/revoke", idempotency_key: idempotency_key)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Download X.509 certificate
|
|
168
|
+
#
|
|
169
|
+
# @return [Hash]
|
|
170
|
+
def certificate(id:, domain: nil)
|
|
171
|
+
@client.get("/api/v1/account/signing_keys/#{id}/certificate", params: { domain: domain })
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Webhooks resource operations
|
|
176
|
+
# @api private
|
|
177
|
+
class WebhooksResource
|
|
178
|
+
# @api private
|
|
179
|
+
def initialize(client)
|
|
180
|
+
@client = client
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# List webhooks
|
|
184
|
+
#
|
|
185
|
+
# @return [Hash]
|
|
186
|
+
def list
|
|
187
|
+
@client.get("/api/v1/account/webhooks")
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Create webhook
|
|
191
|
+
#
|
|
192
|
+
# @return [Hash]
|
|
193
|
+
def create(body: nil, idempotency_key: nil)
|
|
194
|
+
@client.post("/api/v1/account/webhooks", body: body, idempotency_key: idempotency_key)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Get webhook details
|
|
198
|
+
#
|
|
199
|
+
# @return [Hash]
|
|
200
|
+
def get
|
|
201
|
+
@client.get("/api/v1/account/webhooks/primary")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Update webhook
|
|
205
|
+
#
|
|
206
|
+
# @return [Hash]
|
|
207
|
+
def update(body: nil, idempotency_key: nil)
|
|
208
|
+
@client.patch("/api/v1/account/webhooks/primary", body: body, idempotency_key: idempotency_key)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Delete webhook
|
|
212
|
+
#
|
|
213
|
+
# @return [Hash]
|
|
214
|
+
def delete
|
|
215
|
+
@client.delete("/api/v1/account/webhooks/primary")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Test webhook
|
|
219
|
+
#
|
|
220
|
+
# @return [Hash]
|
|
221
|
+
def test(idempotency_key: nil)
|
|
222
|
+
@client.post("/api/v1/account/webhooks/primary/test", idempotency_key: idempotency_key)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Auto-generated by bin/generate_sdks.rb - DO NOT EDIT
|
|
4
|
+
|
|
5
|
+
module AhoSdk
|
|
6
|
+
# Cursor-paginated response with lazy iteration support
|
|
7
|
+
#
|
|
8
|
+
# @example Iterate through all pages
|
|
9
|
+
# page = issuer.credentials.list
|
|
10
|
+
# page.each do |credential|
|
|
11
|
+
# puts credential[:uuid]
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# @example Manual pagination
|
|
15
|
+
# page = issuer.credentials.list
|
|
16
|
+
# while page
|
|
17
|
+
# page.data.each { |c| puts c[:uuid] }
|
|
18
|
+
# page = page.next_page
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
class CursorPage
|
|
22
|
+
include Enumerable
|
|
23
|
+
|
|
24
|
+
attr_reader :data, :meta
|
|
25
|
+
|
|
26
|
+
# @param data [Array<Hash>] Items on this page
|
|
27
|
+
# @param meta [Hash] Pagination metadata (cursor, has_more, next_cursor)
|
|
28
|
+
# @param fetch_next [Proc] Lambda to fetch the next page given a cursor
|
|
29
|
+
def initialize(data:, meta:, fetch_next:)
|
|
30
|
+
@data = data
|
|
31
|
+
@meta = meta
|
|
32
|
+
@fetch_next = fetch_next
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Iterate through all items across all pages (lazy loading)
|
|
36
|
+
# @yield [Hash] Each item
|
|
37
|
+
# @return [Enumerator] if no block given
|
|
38
|
+
def each(&block)
|
|
39
|
+
return enum_for(:each) unless block_given?
|
|
40
|
+
|
|
41
|
+
page = self
|
|
42
|
+
loop do
|
|
43
|
+
page.data.each(&block)
|
|
44
|
+
page = page.next_page
|
|
45
|
+
break if page.nil?
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Fetch the next page
|
|
50
|
+
# @return [CursorPage, nil] Next page or nil if this is the last page
|
|
51
|
+
def next_page
|
|
52
|
+
return nil unless has_more?
|
|
53
|
+
|
|
54
|
+
cursor = next_cursor
|
|
55
|
+
return nil if cursor.nil?
|
|
56
|
+
|
|
57
|
+
@fetch_next.call(cursor)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Boolean] true if there are more pages
|
|
61
|
+
def has_more?
|
|
62
|
+
meta[:has_more] || meta["has_more"] || false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [String, nil] Cursor for the next page
|
|
66
|
+
def next_cursor
|
|
67
|
+
meta[:next_cursor] || meta["next_cursor"]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [String, nil] Cursor for the current page (if provided)
|
|
71
|
+
def cursor
|
|
72
|
+
meta[:cursor] || meta["cursor"]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [Integer] Number of items per page (if provided)
|
|
76
|
+
def per_page
|
|
77
|
+
meta[:per_page] || meta["per_page"]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Integer] Number of items on this page
|
|
81
|
+
def size
|
|
82
|
+
data.size
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
alias_method :length, :size
|
|
86
|
+
end
|
|
87
|
+
end
|