vortex-ruby-sdk 1.1.3 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2f54f415260bef01b6106dc5d32cf274e4b9c45e00cdd89e18ad6dfbc1df177
4
- data.tar.gz: 32e1ab2a8a7bc1ee1a3a683d82832a301f4e3403289a64ff8eea4c77410dc104
3
+ metadata.gz: ac2c594fa0a88757da59e6df7f87e0d232b25e53035b560bce733c582d953320
4
+ data.tar.gz: 356960f55a08e9c475bf4be6b126510d36ad8251d2988d44c3ede9f3d00598e4
5
5
  SHA512:
6
- metadata.gz: 61262106b17af91ce480f7fac66a79a9d4bf2b7b77c264eba92ea07bf7a82967991e3629b59c84f0edbed77054a4f3f9ac661f9a101a4e28f8dd1efc16deafe9
7
- data.tar.gz: efc03cda77c4d08a66ef056da5d6c72930ce0003bd6418e2cb145a6a95930e0895f7057d4e864c6c78ca7c5a69ac05dca35d0d6e17ea1aec01e480d795244a32
6
+ metadata.gz: f5b8fd2f00a23144c21d87a3cd127bef7dc25d935d78e9a0120048e075c756a5e5db1f3bf6b0a466e7788c626a75e1f91b019acadf2f334ddb9da811ee37fcd0
7
+ data.tar.gz: b4c4a42a681f9cd772cd2310b00692f149e48171ce5c0659f94dc3995a307a5d6c986aa96984aaf403a0ed610c0491718c8c0323771ba308c25a09f586724265
data/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to the Vortex Ruby SDK will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.0] - 2026-01-23
9
+
10
+ ### Added
11
+ - **Internal Invitations**: New `'internal'` delivery type for customer-managed invitations
12
+ - Support for `deliveryTypes: ['internal']`
13
+ - No email/SMS communication triggered by Vortex
14
+ - Target value can be any customer-defined identifier
15
+ - Useful for in-app invitation flows managed by customer's application
16
+
17
+ ### Changed
18
+ - Updated `deliveryTypes` field documentation to include `'internal'` as a valid value
19
+
8
20
  ## [1.1.3] - 2025-01-29
9
21
 
10
22
  ### Added
data/README.md CHANGED
@@ -12,6 +12,8 @@ A Ruby SDK for the Vortex invitation system, providing seamless integration with
12
12
  - **Same Route Structure**: Ensures React provider compatibility
13
13
  - **Comprehensive Testing**: Full test coverage with RSpec
14
14
  - **Type Safety**: Clear method signatures and documentation
15
+ - **Multiple Delivery Types**: Support for `email`, `phone`, `share`, and `internal` invitation delivery
16
+ - `internal` invitations allow for customer-managed, in-app invitation flows with no external communication
15
17
 
16
18
  ## Installation
17
19
 
@@ -45,7 +47,9 @@ client = Vortex::Client.new(ENV['VORTEX_API_KEY'])
45
47
  user = {
46
48
  id: 'user-123',
47
49
  email: 'user@example.com',
48
- admin_scopes: ['autojoin'] # Optional - included as adminScopes array in JWT
50
+ user_name: 'Jane Doe', # Optional: user's display name
51
+ user_avatar_url: 'https://example.com/avatars/jane.jpg', # Optional: user's avatar URL
52
+ admin_scopes: ['autojoin'] # Optional: grants autojoin admin privileges
49
53
  }
50
54
 
51
55
  # Generate JWT
@@ -61,22 +65,6 @@ client.accept_invitations(['inv1', 'inv2'], { type: 'email', value: 'user@exampl
61
65
  group_invitations = client.get_invitations_by_group('team', 'team1')
62
66
  ```
63
67
 
64
- ### Generate JWT with Additional Properties
65
-
66
- ```ruby
67
- user = {
68
- id: 'user-123',
69
- email: 'user@example.com'
70
- }
71
-
72
- extra = {
73
- role: 'admin',
74
- department: 'Engineering'
75
- }
76
-
77
- jwt = client.generate_jwt(user: user, extra: extra)
78
- ```
79
-
80
68
  ## Rails Integration
81
69
 
82
70
  Create a controller with Vortex routes:
data/lib/vortex/client.rb CHANGED
@@ -80,6 +80,16 @@ module Vortex
80
80
  expires: expires
81
81
  }
82
82
 
83
+ # Add name if present (convert snake_case to camelCase for JWT)
84
+ if user[:user_name]
85
+ payload[:userName] = user[:user_name]
86
+ end
87
+
88
+ # Add userAvatarUrl if present (convert snake_case to camelCase for JWT)
89
+ if user[:user_avatar_url]
90
+ payload[:userAvatarUrl] = user[:user_avatar_url]
91
+ end
92
+
83
93
  # Add adminScopes if present
84
94
  if user[:admin_scopes]
85
95
  payload[:adminScopes] = user[:admin_scopes]
@@ -204,7 +214,7 @@ module Vortex
204
214
  case target_type
205
215
  when 'email'
206
216
  user[:email] = target_value
207
- when 'sms', 'phoneNumber'
217
+ when 'phone', 'phoneNumber'
208
218
  user[:phone] = target_value
209
219
  else
210
220
  # For other types, try to use as email
@@ -277,6 +287,102 @@ module Vortex
277
287
  raise VortexError, "Failed to reinvite: #{e.message}"
278
288
  end
279
289
 
290
+ # Create an invitation from your backend
291
+ #
292
+ # This method allows you to create invitations programmatically using your API key,
293
+ # without requiring a user JWT token. Useful for server-side invitation creation,
294
+ # such as "People You May Know" flows or admin-initiated invitations.
295
+ #
296
+ # Target types:
297
+ # - 'email': Send an email invitation
298
+ # - 'phone': Create a phone invitation (short link returned for you to send)
299
+ # - 'internal': Create an internal invitation for PYMK flows (no email sent)
300
+ #
301
+ # @param widget_configuration_id [String] The widget configuration ID to use
302
+ # @param target [Hash] The invitation target: { type: 'email|sms|internal', value: '...' }
303
+ # @param inviter [Hash] The inviter info: { user_id: '...', user_email: '...', name: '...' }
304
+ # @param groups [Array<Hash>, nil] Optional groups: [{ type: '...', group_id: '...', name: '...' }]
305
+ # @param source [String, nil] Optional source for analytics (defaults to 'api')
306
+ # @param subtype [String, nil] Optional subtype for analytics segmentation (e.g., 'pymk', 'find-friends')
307
+ # @param template_variables [Hash, nil] Optional template variables for email customization
308
+ # @param metadata [Hash, nil] Optional metadata passed through to webhooks
309
+ # @param unfurl_config [Hash, nil] Optional link unfurl (Open Graph) config: { title: '...', description: '...', image: '...', type: '...', site_name: '...' }
310
+ # @return [Hash] Created invitation with :id, :short_link, :status, :created_at
311
+ # @raise [VortexError] If the request fails
312
+ #
313
+ # @example Create an email invitation with custom link preview
314
+ # result = client.create_invitation(
315
+ # 'widget-config-123',
316
+ # { type: 'email', value: 'invitee@example.com' },
317
+ # { user_id: 'user-456', user_email: 'inviter@example.com', name: 'John Doe' },
318
+ # [{ type: 'team', group_id: 'team-789', name: 'Engineering' }],
319
+ # nil,
320
+ # nil,
321
+ # nil,
322
+ # { title: 'Join the team!', description: 'You have been invited', image: 'https://example.com/og.png' }
323
+ # )
324
+ #
325
+ # @example Create an internal invitation (PYMK flow - no email sent)
326
+ # result = client.create_invitation(
327
+ # 'widget-config-123',
328
+ # { type: 'internal', value: 'internal-user-abc' },
329
+ # { user_id: 'user-456' },
330
+ # nil,
331
+ # 'pymk'
332
+ # )
333
+ def create_invitation(widget_configuration_id, target, inviter, groups = nil, source = nil, subtype = nil, template_variables = nil, metadata = nil, unfurl_config = nil)
334
+ raise VortexError, 'widget_configuration_id is required' if widget_configuration_id.nil? || widget_configuration_id.empty?
335
+ raise VortexError, 'target must have type and value' if target[:type].nil? || target[:value].nil?
336
+ raise VortexError, 'inviter must have user_id' if inviter[:user_id].nil?
337
+
338
+ # Build request body with camelCase keys for the API
339
+ body = {
340
+ widgetConfigurationId: widget_configuration_id,
341
+ target: target,
342
+ inviter: {
343
+ userId: inviter[:user_id],
344
+ userEmail: inviter[:user_email],
345
+ userName: inviter[:user_name],
346
+ userAvatarUrl: inviter[:user_avatar_url]
347
+ }.compact
348
+ }
349
+
350
+ if groups && !groups.empty?
351
+ body[:groups] = groups.map do |g|
352
+ {
353
+ type: g[:type],
354
+ groupId: g[:group_id],
355
+ name: g[:name]
356
+ }
357
+ end
358
+ end
359
+
360
+ body[:source] = source if source
361
+ body[:subtype] = subtype if subtype
362
+ body[:templateVariables] = template_variables if template_variables
363
+ body[:metadata] = metadata if metadata
364
+ if unfurl_config
365
+ body[:unfurlConfig] = {
366
+ title: unfurl_config[:title],
367
+ description: unfurl_config[:description],
368
+ image: unfurl_config[:image],
369
+ type: unfurl_config[:type],
370
+ siteName: unfurl_config[:site_name]
371
+ }.compact
372
+ end
373
+
374
+ response = @connection.post('/api/v1/invitations') do |req|
375
+ req.headers['Content-Type'] = 'application/json'
376
+ req.body = JSON.generate(body)
377
+ end
378
+
379
+ handle_response(response)
380
+ rescue VortexError
381
+ raise
382
+ rescue => e
383
+ raise VortexError, "Failed to create invitation: #{e.message}"
384
+ end
385
+
280
386
  private
281
387
 
282
388
  def build_connection
data/lib/vortex/types.rb CHANGED
@@ -60,6 +60,21 @@ module Vortex
60
60
  # groups: [INVITATION_GROUP, ...],
61
61
  # # ... other fields
62
62
  # }
63
+ # InvitationTarget represents the target of an invitation
64
+ # @example
65
+ # {
66
+ # type: 'email', # 'email', 'phone', 'share', or 'internal'
67
+ # value: 'user@example.com',
68
+ # name: 'Jane Smith', # Optional: Display name of the person being invited
69
+ # avatarUrl: 'https://...' # Optional: Avatar URL for display in invitation lists
70
+ # }
71
+ INVITATION_TARGET = {
72
+ type: String, # Required: 'email', 'phone', 'share', or 'internal'
73
+ value: String, # Required: Email, phone, or internal ID
74
+ name: String, # Optional: Display name of the person being invited
75
+ avatarUrl: String # Optional: Avatar URL for the person being invited
76
+ }.freeze
77
+
63
78
  INVITATION = {
64
79
  id: String,
65
80
  accountId: String,
@@ -69,12 +84,12 @@ module Vortex
69
84
  createdAt: String,
70
85
  deactivated: :boolean,
71
86
  deliveryCount: Integer,
72
- deliveryTypes: Array, # of String
87
+ deliveryTypes: Array, # of String - valid values: "email", "phone", "share", "internal"
73
88
  foreignCreatorId: String,
74
89
  invitationType: String,
75
90
  modifiedAt: String,
76
91
  status: String,
77
- target: Array, # of { type: String, value: String }
92
+ target: Array, # of INVITATION_TARGET structures
78
93
  views: Integer,
79
94
  widgetConfigurationId: String,
80
95
  projectId: String,
@@ -83,5 +98,20 @@ module Vortex
83
98
  expired: :boolean,
84
99
  expires: String # ISO 8601 timestamp (optional)
85
100
  }.freeze
101
+
102
+ # CreateInvitationTarget for creating invitations
103
+ # @example
104
+ # {
105
+ # type: 'email',
106
+ # value: 'invitee@example.com',
107
+ # name: 'Jane Smith', # Optional
108
+ # avatarUrl: 'https://...' # Optional
109
+ # }
110
+ CREATE_INVITATION_TARGET = {
111
+ type: String, # Required: 'email', 'phone', or 'internal'
112
+ value: String, # Required: Email, phone, or internal ID
113
+ name: String, # Optional: Display name of the person being invited
114
+ avatarUrl: String # Optional: Avatar URL for the person being invited
115
+ }.freeze
86
116
  end
87
117
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vortex
4
- VERSION = '1.1.3'
4
+ VERSION = '1.5.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vortex-ruby-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vortex Software
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-05 00:00:00.000000000 Z
11
+ date: 2026-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday