vortex-ruby-sdk 1.0.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/LICENSE +21 -0
- data/PUBLISHING.md +474 -0
- data/README.md +204 -0
- data/Rakefile +40 -0
- data/examples/basic_usage.rb +72 -0
- data/examples/rails_app.rb +129 -0
- data/examples/sinatra_app.rb +119 -0
- data/lib/vortex/client.rb +229 -0
- data/lib/vortex/error.rb +19 -0
- data/lib/vortex/rails.rb +257 -0
- data/lib/vortex/sinatra.rb +276 -0
- data/lib/vortex/version.rb +5 -0
- data/lib/vortex.rb +55 -0
- data/vortex-ruby-sdk.gemspec +47 -0
- metadata +188 -0
data/lib/vortex/rails.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'vortex/client'
|
4
|
+
require 'vortex/error'
|
5
|
+
|
6
|
+
module Vortex
|
7
|
+
module Rails
|
8
|
+
# Rails controller integration for Vortex SDK
|
9
|
+
#
|
10
|
+
# This module provides the same route structure as other SDKs (Express, Java, Python)
|
11
|
+
# to ensure complete compatibility with React providers and frontend frameworks.
|
12
|
+
#
|
13
|
+
# Usage in Rails controller:
|
14
|
+
# class VortexController < ApplicationController
|
15
|
+
# include Vortex::Rails::Controller
|
16
|
+
#
|
17
|
+
# private
|
18
|
+
#
|
19
|
+
# def authenticate_vortex_user
|
20
|
+
# # Return user data or nil
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def authorize_vortex_operation(operation, user)
|
24
|
+
# # Return true/false
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def vortex_client
|
28
|
+
# @vortex_client ||= Vortex::Client.new(ENV['VORTEX_API_KEY'])
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
module Controller
|
32
|
+
extend ActiveSupport::Concern
|
33
|
+
|
34
|
+
included do
|
35
|
+
# Ensure these routes match exactly with other SDKs for React provider compatibility
|
36
|
+
rescue_from Vortex::VortexError, with: :handle_vortex_error
|
37
|
+
end
|
38
|
+
|
39
|
+
# Generate JWT for authenticated user
|
40
|
+
# POST /api/vortex/jwt
|
41
|
+
def generate_jwt
|
42
|
+
user = authenticate_vortex_user
|
43
|
+
return render_unauthorized('Authentication required') unless user
|
44
|
+
|
45
|
+
unless authorize_vortex_operation('JWT', user)
|
46
|
+
return render_forbidden('Not authorized to generate JWT')
|
47
|
+
end
|
48
|
+
|
49
|
+
jwt = vortex_client.generate_jwt(
|
50
|
+
user_id: user[:user_id],
|
51
|
+
identifiers: user[:identifiers],
|
52
|
+
groups: user[:groups],
|
53
|
+
role: user[:role]
|
54
|
+
)
|
55
|
+
|
56
|
+
render json: { jwt: jwt }
|
57
|
+
rescue Vortex::VortexError => e
|
58
|
+
render_server_error("Failed to generate JWT: #{e.message}")
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get invitations by target
|
62
|
+
# GET /api/vortex/invitations?targetType=email&targetValue=user@example.com
|
63
|
+
def get_invitations_by_target
|
64
|
+
user = authenticate_vortex_user
|
65
|
+
return render_unauthorized('Authentication required') unless user
|
66
|
+
|
67
|
+
unless authorize_vortex_operation('GET_INVITATIONS', user)
|
68
|
+
return render_forbidden('Not authorized to get invitations')
|
69
|
+
end
|
70
|
+
|
71
|
+
target_type = params[:targetType]
|
72
|
+
target_value = params[:targetValue]
|
73
|
+
|
74
|
+
return render_bad_request('Missing targetType or targetValue') unless target_type && target_value
|
75
|
+
|
76
|
+
invitations = vortex_client.get_invitations_by_target(target_type, target_value)
|
77
|
+
render json: { invitations: invitations }
|
78
|
+
rescue Vortex::VortexError => e
|
79
|
+
render_server_error("Failed to get invitations: #{e.message}")
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get specific invitation by ID
|
83
|
+
# GET /api/vortex/invitations/:invitation_id
|
84
|
+
def get_invitation
|
85
|
+
user = authenticate_vortex_user
|
86
|
+
return render_unauthorized('Authentication required') unless user
|
87
|
+
|
88
|
+
unless authorize_vortex_operation('GET_INVITATION', user)
|
89
|
+
return render_forbidden('Not authorized to get invitation')
|
90
|
+
end
|
91
|
+
|
92
|
+
invitation_id = params[:invitation_id]
|
93
|
+
invitation = vortex_client.get_invitation(invitation_id)
|
94
|
+
render json: invitation
|
95
|
+
rescue Vortex::VortexError => e
|
96
|
+
render_not_found("Invitation not found: #{e.message}")
|
97
|
+
end
|
98
|
+
|
99
|
+
# Revoke (delete) invitation
|
100
|
+
# DELETE /api/vortex/invitations/:invitation_id
|
101
|
+
def revoke_invitation
|
102
|
+
user = authenticate_vortex_user
|
103
|
+
return render_unauthorized('Authentication required') unless user
|
104
|
+
|
105
|
+
unless authorize_vortex_operation('REVOKE_INVITATION', user)
|
106
|
+
return render_forbidden('Not authorized to revoke invitation')
|
107
|
+
end
|
108
|
+
|
109
|
+
invitation_id = params[:invitation_id]
|
110
|
+
vortex_client.revoke_invitation(invitation_id)
|
111
|
+
render json: { success: true }
|
112
|
+
rescue Vortex::VortexError => e
|
113
|
+
render_server_error("Failed to revoke invitation: #{e.message}")
|
114
|
+
end
|
115
|
+
|
116
|
+
# Accept invitations
|
117
|
+
# POST /api/vortex/invitations/accept
|
118
|
+
def accept_invitations
|
119
|
+
user = authenticate_vortex_user
|
120
|
+
return render_unauthorized('Authentication required') unless user
|
121
|
+
|
122
|
+
unless authorize_vortex_operation('ACCEPT_INVITATIONS', user)
|
123
|
+
return render_forbidden('Not authorized to accept invitations')
|
124
|
+
end
|
125
|
+
|
126
|
+
invitation_ids = params[:invitationIds]
|
127
|
+
target = params[:target]
|
128
|
+
|
129
|
+
unless invitation_ids && target
|
130
|
+
return render_bad_request('Missing invitationIds or target')
|
131
|
+
end
|
132
|
+
|
133
|
+
result = vortex_client.accept_invitations(invitation_ids, target)
|
134
|
+
render json: result
|
135
|
+
rescue Vortex::VortexError => e
|
136
|
+
render_server_error("Failed to accept invitations: #{e.message}")
|
137
|
+
end
|
138
|
+
|
139
|
+
# Get invitations by group
|
140
|
+
# GET /api/vortex/invitations/by-group/:group_type/:group_id
|
141
|
+
def get_invitations_by_group
|
142
|
+
user = authenticate_vortex_user
|
143
|
+
return render_unauthorized('Authentication required') unless user
|
144
|
+
|
145
|
+
unless authorize_vortex_operation('GET_GROUP_INVITATIONS', user)
|
146
|
+
return render_forbidden('Not authorized to get group invitations')
|
147
|
+
end
|
148
|
+
|
149
|
+
group_type = params[:group_type]
|
150
|
+
group_id = params[:group_id]
|
151
|
+
|
152
|
+
invitations = vortex_client.get_invitations_by_group(group_type, group_id)
|
153
|
+
render json: { invitations: invitations }
|
154
|
+
rescue Vortex::VortexError => e
|
155
|
+
render_server_error("Failed to get group invitations: #{e.message}")
|
156
|
+
end
|
157
|
+
|
158
|
+
# Delete invitations by group
|
159
|
+
# DELETE /api/vortex/invitations/by-group/:group_type/:group_id
|
160
|
+
def delete_invitations_by_group
|
161
|
+
user = authenticate_vortex_user
|
162
|
+
return render_unauthorized('Authentication required') unless user
|
163
|
+
|
164
|
+
unless authorize_vortex_operation('DELETE_GROUP_INVITATIONS', user)
|
165
|
+
return render_forbidden('Not authorized to delete group invitations')
|
166
|
+
end
|
167
|
+
|
168
|
+
group_type = params[:group_type]
|
169
|
+
group_id = params[:group_id]
|
170
|
+
|
171
|
+
vortex_client.delete_invitations_by_group(group_type, group_id)
|
172
|
+
render json: { success: true }
|
173
|
+
rescue Vortex::VortexError => e
|
174
|
+
render_server_error("Failed to delete group invitations: #{e.message}")
|
175
|
+
end
|
176
|
+
|
177
|
+
# Reinvite user
|
178
|
+
# POST /api/vortex/invitations/:invitation_id/reinvite
|
179
|
+
def reinvite
|
180
|
+
user = authenticate_vortex_user
|
181
|
+
return render_unauthorized('Authentication required') unless user
|
182
|
+
|
183
|
+
unless authorize_vortex_operation('REINVITE', user)
|
184
|
+
return render_forbidden('Not authorized to reinvite')
|
185
|
+
end
|
186
|
+
|
187
|
+
invitation_id = params[:invitation_id]
|
188
|
+
result = vortex_client.reinvite(invitation_id)
|
189
|
+
render json: result
|
190
|
+
rescue Vortex::VortexError => e
|
191
|
+
render_server_error("Failed to reinvite: #{e.message}")
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
# These methods should be implemented in the including controller
|
197
|
+
def authenticate_vortex_user
|
198
|
+
raise NotImplementedError, 'authenticate_vortex_user must be implemented'
|
199
|
+
end
|
200
|
+
|
201
|
+
def authorize_vortex_operation(operation, user)
|
202
|
+
raise NotImplementedError, 'authorize_vortex_operation must be implemented'
|
203
|
+
end
|
204
|
+
|
205
|
+
def vortex_client
|
206
|
+
raise NotImplementedError, 'vortex_client must be implemented'
|
207
|
+
end
|
208
|
+
|
209
|
+
# Error response helpers
|
210
|
+
def render_unauthorized(message)
|
211
|
+
render json: { error: message }, status: :unauthorized
|
212
|
+
end
|
213
|
+
|
214
|
+
def render_forbidden(message)
|
215
|
+
render json: { error: message }, status: :forbidden
|
216
|
+
end
|
217
|
+
|
218
|
+
def render_bad_request(message)
|
219
|
+
render json: { error: message }, status: :bad_request
|
220
|
+
end
|
221
|
+
|
222
|
+
def render_not_found(message)
|
223
|
+
render json: { error: message }, status: :not_found
|
224
|
+
end
|
225
|
+
|
226
|
+
def render_server_error(message)
|
227
|
+
render json: { error: message }, status: :internal_server_error
|
228
|
+
end
|
229
|
+
|
230
|
+
def handle_vortex_error(error)
|
231
|
+
Rails.logger.error("Vortex error: #{error.message}")
|
232
|
+
render_server_error(error.message)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Rails routes helper
|
237
|
+
#
|
238
|
+
# Usage in routes.rb:
|
239
|
+
# Rails.application.routes.draw do
|
240
|
+
# mount Vortex::Rails.routes => '/api/vortex'
|
241
|
+
# end
|
242
|
+
def self.routes
|
243
|
+
proc do
|
244
|
+
scope '/api/vortex', controller: 'vortex' do
|
245
|
+
post 'jwt', action: 'generate_jwt'
|
246
|
+
get 'invitations', action: 'get_invitations_by_target'
|
247
|
+
get 'invitations/:invitation_id', action: 'get_invitation'
|
248
|
+
delete 'invitations/:invitation_id', action: 'revoke_invitation'
|
249
|
+
post 'invitations/accept', action: 'accept_invitations'
|
250
|
+
get 'invitations/by-group/:group_type/:group_id', action: 'get_invitations_by_group'
|
251
|
+
delete 'invitations/by-group/:group_type/:group_id', action: 'delete_invitations_by_group'
|
252
|
+
post 'invitations/:invitation_id/reinvite', action: 'reinvite'
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'vortex/client'
|
5
|
+
require 'vortex/error'
|
6
|
+
|
7
|
+
module Vortex
|
8
|
+
module Sinatra
|
9
|
+
# Sinatra application integration for Vortex SDK
|
10
|
+
#
|
11
|
+
# This module provides the same route structure as other SDKs (Express, Java, Python)
|
12
|
+
# to ensure complete compatibility with React providers and frontend frameworks.
|
13
|
+
#
|
14
|
+
# Usage in Sinatra app:
|
15
|
+
# require 'sinatra/base'
|
16
|
+
# require 'vortex/sinatra'
|
17
|
+
#
|
18
|
+
# class MyApp < Sinatra::Base
|
19
|
+
# register Vortex::Sinatra
|
20
|
+
#
|
21
|
+
# configure do
|
22
|
+
# set :vortex_api_key, ENV['VORTEX_API_KEY']
|
23
|
+
# set :vortex_base_url, ENV['VORTEX_BASE_URL'] # optional
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # Implement authentication callbacks
|
27
|
+
# def authenticate_vortex_user
|
28
|
+
# # Return user hash or nil
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def authorize_vortex_operation(operation, user)
|
32
|
+
# # Return true/false
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
def self.registered(app)
|
36
|
+
app.helpers Helpers
|
37
|
+
|
38
|
+
# Ensure these routes match exactly with other SDKs for React provider compatibility
|
39
|
+
|
40
|
+
# Generate JWT for authenticated user
|
41
|
+
# POST /api/vortex/jwt
|
42
|
+
app.post '/api/vortex/jwt' do
|
43
|
+
with_vortex_error_handling do
|
44
|
+
user = authenticate_vortex_user
|
45
|
+
return render_unauthorized('Authentication required') unless user
|
46
|
+
|
47
|
+
unless authorize_vortex_operation('JWT', user)
|
48
|
+
return render_forbidden('Not authorized to generate JWT')
|
49
|
+
end
|
50
|
+
|
51
|
+
jwt = vortex_client.generate_jwt(
|
52
|
+
user_id: user[:user_id],
|
53
|
+
identifiers: user[:identifiers],
|
54
|
+
groups: user[:groups],
|
55
|
+
role: user[:role]
|
56
|
+
)
|
57
|
+
|
58
|
+
render_json({ jwt: jwt })
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get invitations by target
|
63
|
+
# GET /api/vortex/invitations?targetType=email&targetValue=user@example.com
|
64
|
+
app.get '/api/vortex/invitations' do
|
65
|
+
with_vortex_error_handling do
|
66
|
+
user = authenticate_vortex_user
|
67
|
+
return render_unauthorized('Authentication required') unless user
|
68
|
+
|
69
|
+
unless authorize_vortex_operation('GET_INVITATIONS', user)
|
70
|
+
return render_forbidden('Not authorized to get invitations')
|
71
|
+
end
|
72
|
+
|
73
|
+
target_type = params['targetType']
|
74
|
+
target_value = params['targetValue']
|
75
|
+
|
76
|
+
unless target_type && target_value
|
77
|
+
return render_bad_request('Missing targetType or targetValue')
|
78
|
+
end
|
79
|
+
|
80
|
+
invitations = vortex_client.get_invitations_by_target(target_type, target_value)
|
81
|
+
render_json({ invitations: invitations })
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get specific invitation by ID
|
86
|
+
# GET /api/vortex/invitations/:invitation_id
|
87
|
+
app.get '/api/vortex/invitations/:invitation_id' do
|
88
|
+
with_vortex_error_handling do
|
89
|
+
user = authenticate_vortex_user
|
90
|
+
return render_unauthorized('Authentication required') unless user
|
91
|
+
|
92
|
+
unless authorize_vortex_operation('GET_INVITATION', user)
|
93
|
+
return render_forbidden('Not authorized to get invitation')
|
94
|
+
end
|
95
|
+
|
96
|
+
invitation_id = params['invitation_id']
|
97
|
+
invitation = vortex_client.get_invitation(invitation_id)
|
98
|
+
render_json(invitation)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Revoke (delete) invitation
|
103
|
+
# DELETE /api/vortex/invitations/:invitation_id
|
104
|
+
app.delete '/api/vortex/invitations/:invitation_id' do
|
105
|
+
with_vortex_error_handling do
|
106
|
+
user = authenticate_vortex_user
|
107
|
+
return render_unauthorized('Authentication required') unless user
|
108
|
+
|
109
|
+
unless authorize_vortex_operation('REVOKE_INVITATION', user)
|
110
|
+
return render_forbidden('Not authorized to revoke invitation')
|
111
|
+
end
|
112
|
+
|
113
|
+
invitation_id = params['invitation_id']
|
114
|
+
vortex_client.revoke_invitation(invitation_id)
|
115
|
+
render_json({ success: true })
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Accept invitations
|
120
|
+
# POST /api/vortex/invitations/accept
|
121
|
+
app.post '/api/vortex/invitations/accept' do
|
122
|
+
with_vortex_error_handling do
|
123
|
+
user = authenticate_vortex_user
|
124
|
+
return render_unauthorized('Authentication required') unless user
|
125
|
+
|
126
|
+
unless authorize_vortex_operation('ACCEPT_INVITATIONS', user)
|
127
|
+
return render_forbidden('Not authorized to accept invitations')
|
128
|
+
end
|
129
|
+
|
130
|
+
request_body = parse_json_body
|
131
|
+
|
132
|
+
invitation_ids = request_body['invitationIds']
|
133
|
+
target = request_body['target']
|
134
|
+
|
135
|
+
unless invitation_ids && target
|
136
|
+
return render_bad_request('Missing invitationIds or target')
|
137
|
+
end
|
138
|
+
|
139
|
+
result = vortex_client.accept_invitations(invitation_ids, target)
|
140
|
+
render_json(result)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Get invitations by group
|
145
|
+
# GET /api/vortex/invitations/by-group/:group_type/:group_id
|
146
|
+
app.get '/api/vortex/invitations/by-group/:group_type/:group_id' do
|
147
|
+
with_vortex_error_handling do
|
148
|
+
user = authenticate_vortex_user
|
149
|
+
return render_unauthorized('Authentication required') unless user
|
150
|
+
|
151
|
+
unless authorize_vortex_operation('GET_GROUP_INVITATIONS', user)
|
152
|
+
return render_forbidden('Not authorized to get group invitations')
|
153
|
+
end
|
154
|
+
|
155
|
+
group_type = params['group_type']
|
156
|
+
group_id = params['group_id']
|
157
|
+
|
158
|
+
invitations = vortex_client.get_invitations_by_group(group_type, group_id)
|
159
|
+
render_json({ invitations: invitations })
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Delete invitations by group
|
164
|
+
# DELETE /api/vortex/invitations/by-group/:group_type/:group_id
|
165
|
+
app.delete '/api/vortex/invitations/by-group/:group_type/:group_id' do
|
166
|
+
with_vortex_error_handling do
|
167
|
+
user = authenticate_vortex_user
|
168
|
+
return render_unauthorized('Authentication required') unless user
|
169
|
+
|
170
|
+
unless authorize_vortex_operation('DELETE_GROUP_INVITATIONS', user)
|
171
|
+
return render_forbidden('Not authorized to delete group invitations')
|
172
|
+
end
|
173
|
+
|
174
|
+
group_type = params['group_type']
|
175
|
+
group_id = params['group_id']
|
176
|
+
|
177
|
+
vortex_client.delete_invitations_by_group(group_type, group_id)
|
178
|
+
render_json({ success: true })
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Reinvite user
|
183
|
+
# POST /api/vortex/invitations/:invitation_id/reinvite
|
184
|
+
app.post '/api/vortex/invitations/:invitation_id/reinvite' do
|
185
|
+
with_vortex_error_handling do
|
186
|
+
user = authenticate_vortex_user
|
187
|
+
return render_unauthorized('Authentication required') unless user
|
188
|
+
|
189
|
+
unless authorize_vortex_operation('REINVITE', user)
|
190
|
+
return render_forbidden('Not authorized to reinvite')
|
191
|
+
end
|
192
|
+
|
193
|
+
invitation_id = params['invitation_id']
|
194
|
+
result = vortex_client.reinvite(invitation_id)
|
195
|
+
render_json(result)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Configure Vortex client
|
200
|
+
app.configure do
|
201
|
+
unless app.respond_to?(:vortex_client)
|
202
|
+
app.set :vortex_client, nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Helper methods for Sinatra apps using Vortex
|
208
|
+
module Helpers
|
209
|
+
def vortex_client
|
210
|
+
@vortex_client ||= begin
|
211
|
+
api_key = settings.vortex_api_key
|
212
|
+
base_url = settings.respond_to?(:vortex_base_url) ? settings.vortex_base_url : nil
|
213
|
+
|
214
|
+
raise 'Vortex API key not configured' unless api_key
|
215
|
+
|
216
|
+
Vortex::Client.new(api_key, base_url: base_url)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def authenticate_vortex_user
|
221
|
+
# Default implementation - should be overridden in app
|
222
|
+
nil
|
223
|
+
end
|
224
|
+
|
225
|
+
def authorize_vortex_operation(operation, user)
|
226
|
+
# Default implementation - should be overridden in app
|
227
|
+
user != nil
|
228
|
+
end
|
229
|
+
|
230
|
+
def with_vortex_error_handling(&block)
|
231
|
+
yield
|
232
|
+
rescue Vortex::VortexError => e
|
233
|
+
logger.error("Vortex error: #{e.message}") if respond_to?(:logger)
|
234
|
+
render_server_error("Vortex error: #{e.message}")
|
235
|
+
rescue => e
|
236
|
+
logger.error("Unexpected error: #{e.message}") if respond_to?(:logger)
|
237
|
+
render_server_error("Internal server error")
|
238
|
+
end
|
239
|
+
|
240
|
+
def parse_json_body
|
241
|
+
request.body.rewind
|
242
|
+
body = request.body.read
|
243
|
+
return {} if body.empty?
|
244
|
+
|
245
|
+
JSON.parse(body)
|
246
|
+
rescue JSON::ParserError
|
247
|
+
halt 400, render_json({ error: 'Invalid JSON in request body' })
|
248
|
+
end
|
249
|
+
|
250
|
+
def render_json(data)
|
251
|
+
content_type :json
|
252
|
+
JSON.generate(data)
|
253
|
+
end
|
254
|
+
|
255
|
+
def render_unauthorized(message)
|
256
|
+
halt 401, render_json({ error: message })
|
257
|
+
end
|
258
|
+
|
259
|
+
def render_forbidden(message)
|
260
|
+
halt 403, render_json({ error: message })
|
261
|
+
end
|
262
|
+
|
263
|
+
def render_bad_request(message)
|
264
|
+
halt 400, render_json({ error: message })
|
265
|
+
end
|
266
|
+
|
267
|
+
def render_not_found(message)
|
268
|
+
halt 404, render_json({ error: message })
|
269
|
+
end
|
270
|
+
|
271
|
+
def render_server_error(message)
|
272
|
+
halt 500, render_json({ error: message })
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
data/lib/vortex.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'vortex/version'
|
4
|
+
require 'vortex/error'
|
5
|
+
require 'vortex/client'
|
6
|
+
|
7
|
+
# Vortex Ruby SDK
|
8
|
+
#
|
9
|
+
# This gem provides a Ruby interface to the Vortex invitation system,
|
10
|
+
# with the same functionality and API compatibility as other Vortex SDKs
|
11
|
+
# (Node.js, Python, Java, Go).
|
12
|
+
#
|
13
|
+
# Features:
|
14
|
+
# - JWT generation with identical algorithm to other SDKs
|
15
|
+
# - Complete invitation management API
|
16
|
+
# - Rails and Sinatra framework integrations
|
17
|
+
# - Same route structure for React provider compatibility
|
18
|
+
#
|
19
|
+
# Basic usage:
|
20
|
+
# require 'vortex'
|
21
|
+
#
|
22
|
+
# client = Vortex::Client.new(ENV['VORTEX_API_KEY'])
|
23
|
+
#
|
24
|
+
# jwt = client.generate_jwt(
|
25
|
+
# user_id: 'user123',
|
26
|
+
# identifiers: [{ type: 'email', value: 'user@example.com' }],
|
27
|
+
# groups: [{ id: 'team1', type: 'team', name: 'Engineering' }],
|
28
|
+
# role: 'admin'
|
29
|
+
# )
|
30
|
+
#
|
31
|
+
# Framework integrations:
|
32
|
+
# # Rails
|
33
|
+
# require 'vortex/rails'
|
34
|
+
#
|
35
|
+
# # Sinatra
|
36
|
+
# require 'vortex/sinatra'
|
37
|
+
module Vortex
|
38
|
+
class << self
|
39
|
+
# Create a new Vortex client instance
|
40
|
+
#
|
41
|
+
# @param api_key [String] Your Vortex API key
|
42
|
+
# @param base_url [String] Custom base URL (optional)
|
43
|
+
# @return [Vortex::Client] A new client instance
|
44
|
+
def new(api_key, base_url: nil)
|
45
|
+
Client.new(api_key, base_url: base_url)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get the current version of the SDK
|
49
|
+
#
|
50
|
+
# @return [String] Version string
|
51
|
+
def version
|
52
|
+
VERSION
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/vortex/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'vortex-ruby-sdk'
|
7
|
+
spec.version = Vortex::VERSION
|
8
|
+
spec.authors = ['Vortex Software']
|
9
|
+
spec.email = ['support@vortexsoftware.io']
|
10
|
+
|
11
|
+
spec.summary = 'Ruby SDK for Vortex invitation system'
|
12
|
+
spec.description = 'A Ruby SDK that provides seamless integration with the Vortex invitation system, including JWT generation and invitation management.'
|
13
|
+
spec.homepage = 'https://github.com/vortexsoftware/vortex-ruby-sdk'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = '>= 3.0.0'
|
16
|
+
|
17
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
19
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
20
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
(File.expand_path(f) == __FILE__) ||
|
26
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
spec.bindir = 'exe'
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
# Runtime dependencies
|
34
|
+
spec.add_dependency 'faraday', '~> 2.0'
|
35
|
+
spec.add_dependency 'faraday-net_http', '~> 3.0'
|
36
|
+
|
37
|
+
# Framework integration dependencies (optional)
|
38
|
+
spec.add_dependency 'rack', '>= 2.0'
|
39
|
+
|
40
|
+
# Development dependencies
|
41
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
42
|
+
spec.add_development_dependency 'webmock', '~> 3.0'
|
43
|
+
spec.add_development_dependency 'rubocop', '~> 1.0'
|
44
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
45
|
+
spec.add_development_dependency 'bundler', '>= 2.0'
|
46
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
47
|
+
end
|