vortex-ruby-sdk 1.9.0 → 1.18.0.pre.20260427181620
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/.claude/implementation-guide.md +55 -29
- data/README.md +679 -210
- data/examples/basic_usage.rb +1 -1
- data/examples/rails_app.rb +6 -6
- data/examples/sinatra_app.rb +4 -4
- data/lib/vortex/client.rb +324 -36
- data/lib/vortex/rails.rb +14 -14
- data/lib/vortex/sinatra.rb +10 -10
- data/lib/vortex/types.rb +11 -7
- data/lib/vortex/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0c1d76a55b4ddd17c08d1dcbd45a393e9bed146e1e76dcc0526bcd80fa57710e
|
|
4
|
+
data.tar.gz: 6ccf49c2301554141b1591e674147b58f9841dd5471106d057611c5731685fab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 98cf940bc167c1c6a5d81875829a6281a15bd570ff17bff5430fce7f881d761840979507533e8926deddb4bb8bae970b5d80a2a0b9c80bc61d42efa4e51350d3
|
|
7
|
+
data.tar.gz: 53de4c4f581d6fc5a251887f4159a013f712da9e5f86a13cd442c00eef8deaaaa7af1e206374bb3163819ada40d5cb9509d99a6d4727b102a8f728c7da15b878
|
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
**Requires:** Ruby 3.0+
|
|
6
6
|
|
|
7
7
|
## Prerequisites
|
|
8
|
+
|
|
8
9
|
From integration contract you need: API endpoint prefix, scope entity, authentication pattern
|
|
9
10
|
From discovery data you need: Ruby framework (Rails, Sinatra), database ORM, auth pattern
|
|
10
11
|
|
|
11
12
|
## Key Facts
|
|
13
|
+
|
|
12
14
|
- Framework-agnostic Ruby SDK
|
|
13
15
|
- Client-based: instantiate `Vortex::Client` class and call methods
|
|
14
16
|
- Built-in Rails and Sinatra helpers
|
|
@@ -20,11 +22,13 @@ From discovery data you need: Ruby framework (Rails, Sinatra), database ORM, aut
|
|
|
20
22
|
## Step 1: Install
|
|
21
23
|
|
|
22
24
|
Add to `Gemfile`:
|
|
25
|
+
|
|
23
26
|
```ruby
|
|
24
27
|
gem 'vortex-ruby-sdk'
|
|
25
28
|
```
|
|
26
29
|
|
|
27
30
|
Then install:
|
|
31
|
+
|
|
28
32
|
```bash
|
|
29
33
|
bundle install
|
|
30
34
|
```
|
|
@@ -49,6 +53,7 @@ VORTEX_API_KEY=VRTX.your-api-key-here.secret
|
|
|
49
53
|
## Step 3: Create Vortex Client
|
|
50
54
|
|
|
51
55
|
### Rails Initializer (`config/initializers/vortex.rb`):
|
|
56
|
+
|
|
52
57
|
```ruby
|
|
53
58
|
Rails.application.config.vortex = Vortex::Client.new(
|
|
54
59
|
Rails.application.credentials.vortex_api_key || ENV['VORTEX_API_KEY']
|
|
@@ -56,6 +61,7 @@ Rails.application.config.vortex = Vortex::Client.new(
|
|
|
56
61
|
```
|
|
57
62
|
|
|
58
63
|
### Rails Concern (`app/controllers/concerns/vortex_helper.rb`):
|
|
64
|
+
|
|
59
65
|
```ruby
|
|
60
66
|
module VortexHelper
|
|
61
67
|
extend ActiveSupport::Concern
|
|
@@ -71,6 +77,7 @@ end
|
|
|
71
77
|
```
|
|
72
78
|
|
|
73
79
|
### Sinatra Configuration:
|
|
80
|
+
|
|
74
81
|
```ruby
|
|
75
82
|
# app.rb or config.ru
|
|
76
83
|
require 'sinatra/base'
|
|
@@ -94,6 +101,7 @@ end
|
|
|
94
101
|
## Step 4: Extract Authenticated User
|
|
95
102
|
|
|
96
103
|
### Rails with Devise:
|
|
104
|
+
|
|
97
105
|
```ruby
|
|
98
106
|
# app/controllers/application_controller.rb
|
|
99
107
|
class ApplicationController < ActionController::API
|
|
@@ -116,6 +124,7 @@ end
|
|
|
116
124
|
```
|
|
117
125
|
|
|
118
126
|
### Rails with JWT:
|
|
127
|
+
|
|
119
128
|
```ruby
|
|
120
129
|
class ApplicationController < ActionController::API
|
|
121
130
|
before_action :authenticate_user_from_token!
|
|
@@ -147,6 +156,7 @@ end
|
|
|
147
156
|
```
|
|
148
157
|
|
|
149
158
|
### Sinatra:
|
|
159
|
+
|
|
150
160
|
```ruby
|
|
151
161
|
# app/helpers/auth_helper.rb
|
|
152
162
|
module AuthHelper
|
|
@@ -185,6 +195,7 @@ end
|
|
|
185
195
|
```
|
|
186
196
|
|
|
187
197
|
**Adapt to their patterns:**
|
|
198
|
+
|
|
188
199
|
- Match their auth mechanism (Devise, JWT, sessions)
|
|
189
200
|
- Match their user structure
|
|
190
201
|
- Match their admin detection logic
|
|
@@ -194,6 +205,7 @@ end
|
|
|
194
205
|
## Step 5: Implement JWT Generation Endpoint
|
|
195
206
|
|
|
196
207
|
### Rails (`app/controllers/vortex_controller.rb`):
|
|
208
|
+
|
|
197
209
|
```ruby
|
|
198
210
|
class VortexController < ApplicationController
|
|
199
211
|
before_action :require_authentication!
|
|
@@ -217,6 +229,7 @@ end
|
|
|
217
229
|
```
|
|
218
230
|
|
|
219
231
|
### Sinatra:
|
|
232
|
+
|
|
220
233
|
```ruby
|
|
221
234
|
require 'sinatra/base'
|
|
222
235
|
require 'json'
|
|
@@ -256,6 +269,7 @@ end
|
|
|
256
269
|
## Step 6: Implement Accept Invitations Endpoint (CRITICAL)
|
|
257
270
|
|
|
258
271
|
### Rails Routes (`config/routes.rb`):
|
|
272
|
+
|
|
259
273
|
```ruby
|
|
260
274
|
Rails.application.routes.draw do
|
|
261
275
|
namespace :api do
|
|
@@ -272,6 +286,7 @@ end
|
|
|
272
286
|
```
|
|
273
287
|
|
|
274
288
|
### Rails with ActiveRecord:
|
|
289
|
+
|
|
275
290
|
```ruby
|
|
276
291
|
class Api::VortexController < ApplicationController
|
|
277
292
|
before_action :require_authentication!
|
|
@@ -292,11 +307,11 @@ class Api::VortexController < ApplicationController
|
|
|
292
307
|
invitation_ids.each do |invitation_id|
|
|
293
308
|
invitation = vortex_client.get_invitation(invitation_id)
|
|
294
309
|
|
|
295
|
-
(invitation[
|
|
296
|
-
|
|
310
|
+
(invitation["groups"] || []).each do |scope|
|
|
311
|
+
ScopeMembership.find_or_create_by!(
|
|
297
312
|
user_id: current_user.id,
|
|
298
|
-
|
|
299
|
-
|
|
313
|
+
scope_type: scope['type'],
|
|
314
|
+
scope_id: scope['groupId']
|
|
300
315
|
) do |membership|
|
|
301
316
|
membership.role = invitation['role'] || 'member'
|
|
302
317
|
end
|
|
@@ -320,6 +335,7 @@ end
|
|
|
320
335
|
```
|
|
321
336
|
|
|
322
337
|
### Sinatra with Sequel:
|
|
338
|
+
|
|
323
339
|
```ruby
|
|
324
340
|
post '/api/vortex/invitations/accept' do
|
|
325
341
|
require_authentication!
|
|
@@ -340,14 +356,14 @@ post '/api/vortex/invitations/accept' do
|
|
|
340
356
|
invitation_ids.each do |invitation_id|
|
|
341
357
|
invitation = vortex.get_invitation(invitation_id)
|
|
342
358
|
|
|
343
|
-
(invitation[
|
|
344
|
-
|
|
345
|
-
target: [:user_id, :
|
|
359
|
+
(invitation["groups"] || []).each do |scope|
|
|
360
|
+
ScopeMembership.insert_conflict(
|
|
361
|
+
target: [:user_id, :scope_type, :scope_id],
|
|
346
362
|
update: { role: invitation['role'] || 'member' }
|
|
347
363
|
).insert(
|
|
348
364
|
user_id: current_user.id,
|
|
349
|
-
|
|
350
|
-
|
|
365
|
+
scope_type: scope['type'],
|
|
366
|
+
scope_id: scope['groupId'],
|
|
351
367
|
role: invitation['role'] || 'member',
|
|
352
368
|
joined_at: Time.now
|
|
353
369
|
)
|
|
@@ -368,6 +384,7 @@ end
|
|
|
368
384
|
```
|
|
369
385
|
|
|
370
386
|
**Critical - Adapt database logic:**
|
|
387
|
+
|
|
371
388
|
- Use their actual table/model names (from discovery)
|
|
372
389
|
- Use their actual field names
|
|
373
390
|
- Use their ORM pattern (ActiveRecord, Sequel)
|
|
@@ -378,19 +395,20 @@ end
|
|
|
378
395
|
## Step 7: Database Models
|
|
379
396
|
|
|
380
397
|
### Rails Migration:
|
|
398
|
+
|
|
381
399
|
```ruby
|
|
382
|
-
# db/migrate/
|
|
383
|
-
class
|
|
400
|
+
# db/migrate/YYYYMMDDHHMMSS_create_scope_memberships.rb
|
|
401
|
+
class CreateScopeMemberships < ActiveRecord::Migration[7.0]
|
|
384
402
|
def change
|
|
385
|
-
create_table :
|
|
403
|
+
create_table :scope_memberships do |t|
|
|
386
404
|
t.string :user_id, null: false
|
|
387
|
-
t.string :
|
|
388
|
-
t.string :
|
|
405
|
+
t.string :scope_type, null: false, limit: 100
|
|
406
|
+
t.string :scope_id, null: false
|
|
389
407
|
t.string :role, default: 'member', limit: 50
|
|
390
408
|
t.timestamp :joined_at, null: false, default: -> { 'CURRENT_TIMESTAMP' }
|
|
391
409
|
|
|
392
|
-
t.index [:user_id, :
|
|
393
|
-
t.index [:
|
|
410
|
+
t.index [:user_id, :scope_type, :scope_id], unique: true, name: 'unique_membership'
|
|
411
|
+
t.index [:scope_type, :scope_id], name: 'idx_scope'
|
|
394
412
|
t.index [:user_id], name: 'idx_user'
|
|
395
413
|
end
|
|
396
414
|
end
|
|
@@ -398,33 +416,35 @@ end
|
|
|
398
416
|
```
|
|
399
417
|
|
|
400
418
|
### Rails Model:
|
|
419
|
+
|
|
401
420
|
```ruby
|
|
402
|
-
# app/models/
|
|
403
|
-
class
|
|
421
|
+
# app/models/scope_membership.rb
|
|
422
|
+
class ScopeMembership < ApplicationRecord
|
|
404
423
|
validates :user_id, presence: true
|
|
405
|
-
validates :
|
|
406
|
-
validates :
|
|
424
|
+
validates :scope_type, presence: true
|
|
425
|
+
validates :scope_id, presence: true
|
|
407
426
|
validates :role, presence: true
|
|
408
427
|
|
|
409
|
-
validates :user_id, uniqueness: { scope: [:
|
|
428
|
+
validates :user_id, uniqueness: { scope: [:scope_type, :scope_id] }
|
|
410
429
|
end
|
|
411
430
|
```
|
|
412
431
|
|
|
413
432
|
### Sequel Migration:
|
|
433
|
+
|
|
414
434
|
```ruby
|
|
415
|
-
# db/migrations/
|
|
435
|
+
# db/migrations/001_create_scope_memberships.rb
|
|
416
436
|
Sequel.migration do
|
|
417
437
|
change do
|
|
418
|
-
create_table(:
|
|
438
|
+
create_table(:scope_memberships) do
|
|
419
439
|
primary_key :id
|
|
420
440
|
String :user_id, null: false
|
|
421
|
-
String :
|
|
422
|
-
String :
|
|
441
|
+
String :scope_type, size: 100, null: false
|
|
442
|
+
String :scope_id, null: false
|
|
423
443
|
String :role, size: 50, default: 'member'
|
|
424
444
|
DateTime :joined_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
425
445
|
|
|
426
|
-
index [:user_id, :
|
|
427
|
-
index [:
|
|
446
|
+
index [:user_id, :scope_type, :scope_id], unique: true, name: :unique_membership
|
|
447
|
+
index [:scope_type, :scope_id], name: :idx_scope
|
|
428
448
|
index [:user_id], name: :idx_user
|
|
429
449
|
end
|
|
430
450
|
end
|
|
@@ -450,6 +470,7 @@ curl -X POST http://localhost:3000/api/vortex/jwt \
|
|
|
450
470
|
```
|
|
451
471
|
|
|
452
472
|
Expected response:
|
|
473
|
+
|
|
453
474
|
```json
|
|
454
475
|
{
|
|
455
476
|
"jwt": "eyJhbGciOiJIUzI1NiIs..."
|
|
@@ -471,6 +492,7 @@ Expected response:
|
|
|
471
492
|
**CORS errors** → Add CORS middleware:
|
|
472
493
|
|
|
473
494
|
**Rails:**
|
|
495
|
+
|
|
474
496
|
```ruby
|
|
475
497
|
# Gemfile
|
|
476
498
|
gem 'rack-cors'
|
|
@@ -485,6 +507,7 @@ end
|
|
|
485
507
|
```
|
|
486
508
|
|
|
487
509
|
**Sinatra:**
|
|
510
|
+
|
|
488
511
|
```ruby
|
|
489
512
|
require 'sinatra/cross_origin'
|
|
490
513
|
|
|
@@ -508,13 +531,15 @@ end
|
|
|
508
531
|
## After Implementation Report
|
|
509
532
|
|
|
510
533
|
List files created/modified:
|
|
534
|
+
|
|
511
535
|
- Dependency: Gemfile
|
|
512
536
|
- Client: config/initializers/vortex.rb (or concern)
|
|
513
537
|
- Controller: app/controllers/vortex_controller.rb (or Sinatra routes)
|
|
514
|
-
- Model: app/models/
|
|
515
|
-
- Migration: db/migrate/
|
|
538
|
+
- Model: app/models/scope_membership.rb
|
|
539
|
+
- Migration: db/migrate/XXX_create_scope_memberships.rb
|
|
516
540
|
|
|
517
541
|
Confirm:
|
|
542
|
+
|
|
518
543
|
- Vortex gem installed
|
|
519
544
|
- VortexClient instance created
|
|
520
545
|
- JWT endpoint returns valid JWT
|
|
@@ -525,6 +550,7 @@ Confirm:
|
|
|
525
550
|
## Endpoints Registered
|
|
526
551
|
|
|
527
552
|
All endpoints at `/api/vortex`:
|
|
553
|
+
|
|
528
554
|
- `POST /jwt` - Generate JWT for authenticated user
|
|
529
555
|
- `GET /invitations` - Get invitations by target
|
|
530
556
|
- `GET /invitations/:id` - Get invitation by ID
|