volcano-sdk 0.6.0 → 0.7.1

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: e1c358710803cb0542775a53699fda168e00aa0292d6fe0861287d4175373ecb
4
- data.tar.gz: a1e9f5146e6fd06d956ff7a505f391a72eef8b65cc3a4cf39ae4599a9e1346a5
3
+ metadata.gz: 9d85e7ec311f812ca5267cec7b463ebd65ff82ba44f4ce06e71f23085f7932ea
4
+ data.tar.gz: 772266f8fe5398d085442a03bcf2544468016fc335eb61fb0c1ba04ba47dde35
5
5
  SHA512:
6
- metadata.gz: e5a1dd2cf0df583e5b02d954aeaaa9c63f4d122658605dbf78dac8a4d6f9fade33422742fc54c6f8dae6d22b4019d91aac73519beb2de83913bc4a27cfe160a9
7
- data.tar.gz: 6939426bd9514b8fe97c8e413c61c04acb1559efbcc33afbcf8e6102ac6b09aa96ecc7369859465b1b8f897ce4fe47d8d329ea4ea6fcdaf5aeaa7f52915e444e
6
+ metadata.gz: 2718f112a8e2264f826aa4f3bc89c61f4492ee6034c0913d0e8b64e3d5662e8b89579af0dfbe11a88b2c92fee01c8f7508f90e347a0a7b14f7e4aa3fd40433f4
7
+ data.tar.gz: 773a396b12e6c1b02ed03c5c3d8b4356b39bdac11a222bfecd2817ff0fe6ceee7644d367bb4255f6da90652cf45782efc4fc922e5d2501042ba07d1f1a2847b7
data/README.md CHANGED
@@ -78,7 +78,10 @@ Snapshots contain deeply frozen JSON data. Plain `Time` timestamps become UTC
78
78
  ISO8601 strings with nanosecond precision; symbols become strings. Custom objects,
79
79
  container/string/time subclasses, non-finite numbers, duplicate JSON keys, and
80
80
  structures deeper than 100 levels raise `TypeError`. Use the typed `auth.user`
81
- profile when you need Ruby `Time` values.
81
+ profile when you need Ruby `Time` values. Successful `user`, `update_user`,
82
+ `convert_anonymous`, and `confirm_email_change` calls update this snapshot
83
+ without changing credentials or emitting an authentication-state event.
84
+ Previously returned sessions remain unchanged.
82
85
 
83
86
  ### Get the current user
84
87
 
@@ -89,8 +92,8 @@ raise "wrong user" unless user.id == session.user_id
89
92
 
90
93
  `user` sends the active access token to Volcano and returns an immutable,
91
94
  server-validated `Volcano::User`. The SDK recursively freezes its strings and
92
- metadata, but does not cache the profile or replace the session. A session
93
- change while the request is in flight raises
95
+ metadata and updates `current_session.user`. A session change while the request
96
+ is in flight raises
94
97
  `Volcano::Error::SessionChangedError` instead of returning a stale profile.
95
98
  `get_user` is available as a cross-SDK alias.
96
99
 
@@ -106,8 +109,8 @@ raise "wrong user" unless user.id == session.user_id
106
109
 
107
110
  `update_user` changes the current user's password, metadata, or both. Metadata
108
111
  is a shallow patch: omitted keys remain unchanged, and a `nil` value removes
109
- that key. The method returns an immutable `Volcano::User` without replacing the
110
- active session. It rejects a response if another authentication operation
112
+ that key. The method returns an immutable `Volcano::User` and updates the local
113
+ user snapshot. It rejects a response if another authentication operation
111
114
  replaces the session while the request is in flight.
112
115
 
113
116
  ### Request a password reset email
@@ -170,8 +173,8 @@ user = client.auth.confirm_email_change(token: "email-change-token")
170
173
  puts user.email
171
174
  ```
172
175
 
173
- The method returns the immutable updated user without replacing the active
174
- session. A successful stale response is rejected if another authentication
176
+ The method returns the immutable updated user and updates the local user
177
+ snapshot. A successful stale response is rejected if another authentication
175
178
  operation replaces that session in flight.
176
179
 
177
180
  ### List sessions
@@ -484,7 +487,8 @@ syntax. Both methods require an active user session.
484
487
  rows = client.database("main").from("items").select("*").eq("slug", "a").execute
485
488
  ```
486
489
 
487
- Database selects, inserts, updates, deletes, and log reads refresh the captured
490
+ Database selects, inserts, updates, deletes, log reads, and authenticated storage
491
+ requests (including upload sessions and parts) refresh the captured
488
492
  session after an HTTP 401 and retry the same request once. Concurrent requests reuse a successful
489
493
  refresh for that session.
490
494
  Replacing or signing out the session before replay, or while replay is in flight,
@@ -20,10 +20,7 @@ module Volcano
20
20
  anonymous_conversion_response(current.access_token, email, password, metadata),
21
21
  200
22
22
  )
23
- user = build_user(user_payload(payload))
24
- raise Error::SessionChangedError unless @client.capture_session.first == generation
25
-
26
- user
23
+ cache_current_user(payload, generation)
27
24
  end
28
25
 
29
26
  private
@@ -30,10 +30,7 @@ module Volcano
30
30
  raise Error::AuthenticationError, 'No active session' unless current
31
31
 
32
32
  payload = Transport.body(confirm_email_change_response(current.access_token, token), 200)
33
- user = build_user(user_payload(payload))
34
- raise Error::SessionChangedError unless @client.capture_session.first == generation
35
-
36
- user
33
+ cache_current_user(payload, generation)
37
34
  end
38
35
 
39
36
  private
@@ -19,16 +19,21 @@ module Volcano
19
19
  raise Error::AuthenticationError, 'No active session' unless current
20
20
 
21
21
  payload = Transport.body(get_user_response(current.access_token), 200)
22
- user = build_user(user_payload(payload))
23
- raise Error::SessionChangedError unless @client.capture_session.first == generation
24
-
25
- user
22
+ cache_current_user(payload, generation)
26
23
  end
27
24
 
28
25
  alias get_user user
29
26
 
30
27
  private
31
28
 
29
+ def cache_current_user(payload, generation)
30
+ profile = user_payload(payload)
31
+ user = build_user(profile)
32
+ raise Error::SessionChangedError unless @client.update_session_user_if_current?(profile, generation)
33
+
34
+ user
35
+ end
36
+
32
37
  def get_user_response(access_token)
33
38
  Transport.invoke do
34
39
  @transport.auth_get_user(authorization: access_token)
@@ -10,10 +10,10 @@ module Volcano
10
10
  refresh_captured_session(binding)
11
11
  end
12
12
 
13
- def session_request
14
- binding = @client.capture_session_binding
13
+ def session_request(binding: @client.capture_session_binding)
15
14
  raise Error::AuthenticationError, 'No active session' unless binding.last
16
15
 
16
+ binding = owned_session_binding(binding)
17
17
  response = yield(binding.last.access_token)
18
18
  return response unless response.status == 401
19
19
 
@@ -65,10 +65,10 @@ module Volcano
65
65
  active = @client.capture_session_binding
66
66
  raise Error::AuthenticationError, 'No active session' if rejected_refresh?(binding, active)
67
67
 
68
- generation, active_lineage, current = active
68
+ _, active_lineage, current = active
69
69
  raise Error::SessionChangedError unless current && active_lineage == binding[1]
70
70
 
71
- [generation, current]
71
+ active
72
72
  end
73
73
 
74
74
  def rejected_refresh?(binding, active)
@@ -50,10 +50,9 @@ module Volcano
50
50
 
51
51
  def store_if_current?(session, generation, event: :signed_in, notifications: nil)
52
52
  dispatch = @mutex.synchronize do
53
- callbacks = replace_if_current(session, generation, event)
54
- return false unless callbacks
53
+ return false unless generation == @generation
55
54
 
56
- enqueue_notification(callbacks, event, session)
55
+ enqueue_notification(replace(session, event), event, session)
57
56
  end
58
57
  return true unless dispatch
59
58
 
@@ -61,6 +60,16 @@ module Volcano
61
60
  true
62
61
  end
63
62
 
63
+ def update_user_if_current?(user, generation)
64
+ @mutex.synchronize do
65
+ return false unless generation == @generation && @session
66
+ raise Error::AuthenticationError, 'Profile belongs to a different user' unless user['id'] == @session.user_id
67
+
68
+ @session = Session.new(**@session.to_h, user: user)
69
+ true
70
+ end
71
+ end
72
+
64
73
  def subscribe(&callback)
65
74
  callback_id, dispatch = @mutex.synchronize do
66
75
  id, current = register(callback)
@@ -79,12 +88,6 @@ module Volcano
79
88
  @callbacks.keys
80
89
  end
81
90
 
82
- def replace_if_current(session, generation, event)
83
- return unless generation == @generation
84
-
85
- replace(session, event)
86
- end
87
-
88
91
  def register(callback)
89
92
  callback_id = @next_callback_id
90
93
  @next_callback_id += 1
@@ -130,7 +133,7 @@ module Volcano
130
133
  def notify(callback_ids, event, session)
131
134
  failure = nil
132
135
  callback_ids.each do |callback_id|
133
- notify_callback(callback_id, event, session)
136
+ @mutex.synchronize { @callbacks[callback_id] }&.call(event, session)
134
137
  rescue StandardError => e
135
138
  Warning.warn("Volcano auth-state callback failed (#{e.class})\n")
136
139
  rescue *CALLBACK_FAILURES => e
@@ -139,10 +142,5 @@ module Volcano
139
142
  end
140
143
  failure
141
144
  end
142
-
143
- def notify_callback(callback_id, event, session)
144
- callback = @mutex.synchronize { @callbacks[callback_id] }
145
- callback&.call(event, session)
146
- end
147
145
  end
148
146
  end
@@ -11,10 +11,7 @@ module Volcano
11
11
  update_user_response(current.access_token, password:, metadata:),
12
12
  200
13
13
  )
14
- user = build_user(user_payload(payload))
15
- raise Error::SessionChangedError unless @client.capture_session.first == generation
16
-
17
- user
14
+ cache_current_user(payload, generation)
18
15
  end
19
16
 
20
17
  private
@@ -49,8 +49,8 @@ module Volcano
49
49
  session.access_token
50
50
  end
51
51
 
52
- def session_request(&)
53
- @auth.session_request(&)
52
+ def session_request(...)
53
+ @auth.session_request(...)
54
54
  end
55
55
 
56
56
  alias session_read session_request
@@ -89,6 +89,10 @@ module Volcano
89
89
  @auth_state.subscribe(...)
90
90
  end
91
91
 
92
+ def update_session_user_if_current?(...)
93
+ @auth_state.update_user_if_current?(...)
94
+ end
95
+
92
96
  private
93
97
 
94
98
  def database_with_token(name, token)
@@ -28,7 +28,7 @@ module Volcano
28
28
  def initialize(client, transport, name, api_url:, anon_key:)
29
29
  @client = client
30
30
  @transport = transport
31
- @name = name
31
+ @name = name.dup.freeze
32
32
  @api_url = api_url.dup.freeze
33
33
  @anon_key = anon_key.dup.freeze
34
34
  freeze
@@ -36,12 +36,16 @@ module Volcano
36
36
 
37
37
  def upload(path, value, content_type: nil)
38
38
  mime_type = upload_content_type(content_type)
39
- response = Transport.invoke do
39
+ path = storage_paths(path).first
40
+ binding = @client.capture_session_binding
41
+ @client.session_token
42
+ content = upload_bytes(value).freeze
43
+ response = storage_request(binding: binding) do |token|
40
44
  @transport.upload_storage_object(
41
- authorization: @client.session_token,
45
+ authorization: token,
42
46
  bucket_name: @name,
43
47
  path: path,
44
- data: upload_bytes(value),
48
+ data: content,
45
49
  content_type: mime_type
46
50
  )
47
51
  end
@@ -49,9 +53,11 @@ module Volcano
49
53
  end
50
54
 
51
55
  def download(path, range: nil)
52
- response = Transport.invoke do
56
+ path = storage_paths(path).first
57
+ range = range&.dup&.freeze
58
+ response = storage_request do |token|
53
59
  @transport.download_storage_object(
54
- authorization: @client.session_token,
60
+ authorization: token,
55
61
  bucket_name: @name,
56
62
  path: path,
57
63
  byte_range: range
@@ -63,9 +69,11 @@ module Volcano
63
69
  end
64
70
 
65
71
  def list(prefix = '', limit: nil, cursor: nil)
66
- response = Transport.invoke do
72
+ prefix = prefix.dup.freeze
73
+ cursor = cursor&.dup&.freeze
74
+ response = storage_request do |token|
67
75
  @transport.list_storage_objects(
68
- authorization: @client.session_token,
76
+ authorization: token,
69
77
  bucket_name: @name,
70
78
  prefix: prefix,
71
79
  limit: limit,
@@ -82,6 +90,10 @@ module Volcano
82
90
 
83
91
  private
84
92
 
93
+ def storage_request(binding: @client.capture_session_binding)
94
+ @client.session_request(binding: binding) { |token| Transport.invoke { yield(token) } }
95
+ end
96
+
85
97
  def upload_content_type(value)
86
98
  return if value.nil?
87
99
  return value.dup.freeze if value.is_a?(String) && value.match?(/\A[\x20-\x7e]+\z/) && !value.strip.empty?
@@ -5,16 +5,16 @@ module Volcano
5
5
  class StorageBucket
6
6
  def remove(paths)
7
7
  deleted = storage_paths(paths)
8
- authorization = @client.session_token
9
- deleted.each { |path| delete_path(path, authorization) }
8
+ binding = @client.capture_session_binding
9
+ deleted.each { |path| delete_path(path, binding) }
10
10
  deleted
11
11
  end
12
12
 
13
13
  def move(from_path, to_path)
14
14
  source, destination = storage_paths([from_path, to_path])
15
- response = Transport.invoke do
15
+ response = storage_request do |token|
16
16
  @transport.move_storage_object(
17
- authorization: @client.session_token,
17
+ authorization: token,
18
18
  bucket_name: @name,
19
19
  from_path: source,
20
20
  to_path: destination
@@ -25,9 +25,9 @@ module Volcano
25
25
 
26
26
  def copy(from_path, to_path)
27
27
  source, destination = storage_paths([from_path, to_path])
28
- response = Transport.invoke do
28
+ response = storage_request do |token|
29
29
  @transport.copy_storage_object(
30
- authorization: @client.session_token,
30
+ authorization: token,
31
31
  bucket_name: @name,
32
32
  from_path: source,
33
33
  to_path: destination
@@ -39,9 +39,9 @@ module Volcano
39
39
  def update_visibility(path, public:)
40
40
  object_path = storage_paths(path).fetch(0)
41
41
  visibility = visibility_value(public)
42
- response = Transport.invoke do
42
+ response = storage_request do |token|
43
43
  @transport.update_storage_object_visibility(
44
- authorization: @client.session_token,
44
+ authorization: token,
45
45
  bucket_name: @name,
46
46
  path: object_path,
47
47
  is_public: visibility
@@ -61,10 +61,10 @@ module Volcano
61
61
  path_list.map { |path| path.dup.freeze }.freeze
62
62
  end
63
63
 
64
- def delete_path(path, authorization)
65
- response = Transport.invoke do
64
+ def delete_path(path, binding)
65
+ response = storage_request(binding: binding) do |token|
66
66
  @transport.delete_storage_object(
67
- authorization: authorization,
67
+ authorization: token,
68
68
  bucket_name: @name,
69
69
  path: path
70
70
  )
@@ -15,9 +15,9 @@ module Volcano
15
15
  total_size: total_size,
16
16
  part_size: part_size
17
17
  )
18
- response = Transport.invoke do
18
+ response = storage_request do |token|
19
19
  @transport.create_upload_session(
20
- authorization: @client.session_token,
20
+ authorization: token,
21
21
  bucket_name: @name,
22
22
  request: request
23
23
  )
@@ -32,9 +32,9 @@ module Volcano
32
32
  part_number: part_number,
33
33
  data: upload_bytes(data)
34
34
  )
35
- response = Transport.invoke do
35
+ response = storage_request do |token|
36
36
  @transport.upload_part(
37
- authorization: @client.session_token,
37
+ authorization: token,
38
38
  bucket_name: @name,
39
39
  request: request
40
40
  )
@@ -44,9 +44,9 @@ module Volcano
44
44
 
45
45
  def complete_upload_session(path, session_id:)
46
46
  request = UploadSessionReference.new(path: path, session_id: session_id)
47
- response = Transport.invoke do
47
+ response = storage_request do |token|
48
48
  @transport.complete_upload_session(
49
- authorization: @client.session_token,
49
+ authorization: token,
50
50
  bucket_name: @name,
51
51
  request: request
52
52
  )
@@ -56,9 +56,9 @@ module Volcano
56
56
 
57
57
  def get_upload_session(path, session_id:)
58
58
  request = UploadSessionReference.new(path: path, session_id: session_id)
59
- response = Transport.invoke do
59
+ response = storage_request do |token|
60
60
  @transport.get_upload_session(
61
- authorization: @client.session_token,
61
+ authorization: token,
62
62
  bucket_name: @name,
63
63
  request: request
64
64
  )
@@ -68,9 +68,9 @@ module Volcano
68
68
 
69
69
  def abort_upload_session(path, session_id:)
70
70
  request = UploadSessionReference.new(path: path, session_id: session_id)
71
- response = Transport.invoke do
71
+ response = storage_request do |token|
72
72
  @transport.abort_upload_session(
73
- authorization: @client.session_token,
73
+ authorization: token,
74
74
  bucket_name: @name,
75
75
  request: request
76
76
  )
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Volcano
4
- VERSION = '0.6.0'
4
+ VERSION = '0.7.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: volcano-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kong