parse-stack-next 5.6.0 → 5.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 +4 -4
- data/CHANGELOG.md +489 -0
- data/README.md +378 -6
- data/docs/caching.md +748 -0
- data/examples/basic_client.rb +3 -3
- data/examples/basic_server.rb +3 -3
- data/examples/live_query_listener.rb +12 -12
- data/examples/rag_chatbot.rb +14 -14
- data/examples/transaction_example.rb +44 -45
- data/examples/webhook_server.rb +3 -3
- data/lib/parse/access.rb +493 -0
- data/lib/parse/acl_scope.rb +125 -52
- data/lib/parse/agent/approval_gate.rb +0 -0
- data/lib/parse/agent/cancellation_token.rb +3 -3
- data/lib/parse/agent/constraint_translator.rb +4 -4
- data/lib/parse/agent/describe.rb +34 -34
- data/lib/parse/agent/errors.rb +9 -9
- data/lib/parse/agent/mcp_client.rb +61 -59
- data/lib/parse/agent/mcp_dispatcher.rb +89 -101
- data/lib/parse/agent/mcp_rack_app.rb +92 -93
- data/lib/parse/agent/mcp_server.rb +1 -1
- data/lib/parse/agent/mcp_subscriptions.rb +22 -22
- data/lib/parse/agent/metadata_audit.rb +1 -2
- data/lib/parse/agent/metadata_dsl.rb +7 -7
- data/lib/parse/agent/metadata_registry.rb +12 -12
- data/lib/parse/agent/prompt_hardening.rb +4 -4
- data/lib/parse/agent/prompts.rb +10 -10
- data/lib/parse/agent/result_formatter.rb +4 -4
- data/lib/parse/agent/tools.rb +493 -400
- data/lib/parse/agent.rb +157 -116
- data/lib/parse/api/hooks.rb +1 -1
- data/lib/parse/api/server.rb +2 -2
- data/lib/parse/api/users.rb +2 -2
- data/lib/parse/atlas_search/index_manager.rb +1 -1
- data/lib/parse/atlas_search/session.rb +40 -218
- data/lib/parse/atlas_search.rb +181 -60
- data/lib/parse/authorization.rb +466 -0
- data/lib/parse/cache/invalidation.rb +219 -0
- data/lib/parse/cache/keyspace.rb +306 -0
- data/lib/parse/cache/moneta_surface.rb +126 -0
- data/lib/parse/cache/pool.rb +48 -5
- data/lib/parse/cache/redis.rb +425 -10
- data/lib/parse/cache/scoped_view.rb +443 -0
- data/lib/parse/cache/sub_cache.rb +264 -0
- data/lib/parse/cache/upstream_roles.rb +230 -0
- data/lib/parse/client/authentication.rb +1 -1
- data/lib/parse/client/body_builder.rb +1 -2
- data/lib/parse/client/caching.rb +84 -5
- data/lib/parse/client.rb +327 -189
- data/lib/parse/clp_scope.rb +225 -28
- data/lib/parse/console.rb +3 -3
- data/lib/parse/embeddings/batch_embedder.rb +3 -3
- data/lib/parse/embeddings/cache.rb +17 -17
- data/lib/parse/embeddings/cohere.rb +21 -22
- data/lib/parse/embeddings/image_fetch.rb +22 -21
- data/lib/parse/embeddings/jina.rb +21 -21
- data/lib/parse/embeddings/local_http.rb +6 -7
- data/lib/parse/embeddings/media_file.rb +5 -4
- data/lib/parse/embeddings/openai.rb +5 -5
- data/lib/parse/embeddings/provider.rb +1 -1
- data/lib/parse/embeddings/qwen.rb +10 -10
- data/lib/parse/embeddings/spend_cap.rb +2 -3
- data/lib/parse/embeddings/streaming_body.rb +11 -11
- data/lib/parse/embeddings/video_source.rb +7 -6
- data/lib/parse/embeddings/voyage.rb +59 -61
- data/lib/parse/embeddings.rb +28 -27
- data/lib/parse/graphql/type_generator.rb +1 -1
- data/lib/parse/graphql.rb +5 -5
- data/lib/parse/live_query/client.rb +1 -1
- data/lib/parse/live_query.rb +1 -1
- data/lib/parse/lock.rb +15 -18
- data/lib/parse/lock_backend.rb +1 -1
- data/lib/parse/lookup_rewriter.rb +6 -6
- data/lib/parse/model/associations/belongs_to.rb +4 -0
- data/lib/parse/model/associations/collection_proxy.rb +3 -0
- data/lib/parse/model/associations/has_many.rb +4 -0
- data/lib/parse/model/classes/role.rb +227 -28
- data/lib/parse/model/classes/user.rb +60 -1
- data/lib/parse/model/clp.rb +4 -4
- data/lib/parse/model/core/actions.rb +366 -113
- data/lib/parse/model/core/create_lock.rb +0 -2
- data/lib/parse/model/core/describe.rb +57 -57
- data/lib/parse/model/core/embed_managed.rb +21 -23
- data/lib/parse/model/core/fetching.rb +6 -0
- data/lib/parse/model/core/indexing.rb +14 -14
- data/lib/parse/model/core/parse_reference.rb +1 -1
- data/lib/parse/model/core/properties.rb +6 -2
- data/lib/parse/model/core/querying.rb +1 -1
- data/lib/parse/model/core/schema.rb +2 -2
- data/lib/parse/model/core/search_indexing.rb +2 -2
- data/lib/parse/model/core/vector_searchable.rb +4 -5
- data/lib/parse/model/file.rb +21 -15
- data/lib/parse/model/geojson.rb +2 -2
- data/lib/parse/model/geopoint.rb +1 -0
- data/lib/parse/model/object.rb +136 -66
- data/lib/parse/model/pointer.rb +2 -0
- data/lib/parse/model/polygon.rb +3 -6
- data/lib/parse/model/push.rb +2 -2
- data/lib/parse/model/vector.rb +3 -1
- data/lib/parse/mongodb.rb +512 -282
- data/lib/parse/pipeline_security.rb +3 -0
- data/lib/parse/query/constraints.rb +46 -46
- data/lib/parse/query.rb +146 -59
- data/lib/parse/retrieval/agent_tool.rb +34 -20
- data/lib/parse/retrieval/chunk.rb +1 -0
- data/lib/parse/retrieval/reranker/cohere.rb +11 -11
- data/lib/parse/retrieval/reranker.rb +3 -4
- data/lib/parse/retrieval/retriever.rb +4 -6
- data/lib/parse/schema/index_migrator.rb +26 -26
- data/lib/parse/schema/search_index_migrator.rb +19 -19
- data/lib/parse/stack/tasks.rb +6 -6
- data/lib/parse/stack/version.rb +1 -1
- data/lib/parse/stack.rb +10 -10
- data/lib/parse/vector_search/hybrid.rb +66 -41
- data/lib/parse/vector_search.rb +14 -11
- data/lib/parse/webhooks/payload.rb +1 -0
- data/lib/parse/webhooks/registration.rb +4 -4
- data/lib/parse/webhooks/trigger_audit.rb +50 -49
- data/lib/parse/webhooks.rb +120 -5
- data/parse-stack-next.gemspec +6 -6
- metadata +10 -1
data/lib/parse/atlas_search.rb
CHANGED
|
@@ -93,39 +93,85 @@ module Parse
|
|
|
93
93
|
# @return [Boolean]
|
|
94
94
|
attr_accessor :require_session_token
|
|
95
95
|
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
96
|
+
# --- authorization state: delegated, no longer stored here ----------
|
|
97
|
+
#
|
|
98
|
+
# These five used to be module-level ivars on Atlas Search, which made
|
|
99
|
+
# Atlas Search the owner of identity and role resolution for the whole
|
|
100
|
+
# SDK: `Parse::ACLScope` reached through this namespace, and
|
|
101
|
+
# `Parse::MongoDB.aggregate` reaches through `Parse::ACLScope`, so a
|
|
102
|
+
# plain mongo-direct query with no `$search` in it depended on them.
|
|
103
|
+
# They now read and write the DEFAULT client's
|
|
104
|
+
# {Parse::Authorization::Context}. See {Parse::Authorization}.
|
|
105
|
+
#
|
|
106
|
+
# Being module-level, they can only ever address `Parse.client`. Code
|
|
107
|
+
# running against a secondary application must use
|
|
108
|
+
# `other_client.authorization` directly, which is the whole reason the
|
|
109
|
+
# state moved onto the client.
|
|
110
|
+
#
|
|
111
|
+
# Slated for removal in 6.0.
|
|
112
|
+
|
|
113
|
+
# @deprecated Use `client.authorization.identity_cache_ttl`.
|
|
114
|
+
# Renamed because it never stored sessions: it stores one user id per
|
|
115
|
+
# token, and the old name led readers to reason about `_Session`
|
|
116
|
+
# semantics that were never involved.
|
|
117
|
+
def session_cache_ttl = authorization&.identity_cache_ttl || Parse::Authorization::Context::DEFAULT_IDENTITY_TTL
|
|
118
|
+
|
|
119
|
+
def session_cache_ttl=(value)
|
|
120
|
+
authorization&.identity_cache_ttl = value
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# @deprecated Use `client.authorization.role_cache_ttl`.
|
|
124
|
+
def role_cache_ttl = authorization&.role_cache_ttl || Parse::Authorization::Context::DEFAULT_ROLE_TTL
|
|
125
|
+
|
|
126
|
+
def role_cache_ttl=(value)
|
|
127
|
+
authorization&.role_cache_ttl = value
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @deprecated Use `client.authorization.identity_cache`.
|
|
131
|
+
def session_cache = authorization&.identity_cache
|
|
132
|
+
|
|
133
|
+
def session_cache=(value)
|
|
134
|
+
authorization&.identity_cache = value
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# @deprecated Use `client.authorization.role_cache`.
|
|
138
|
+
def role_cache = authorization&.role_cache
|
|
139
|
+
|
|
140
|
+
def role_cache=(value)
|
|
141
|
+
authorization&.role_cache = value
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @deprecated Use `client.authorization.upstream_role_reader`.
|
|
145
|
+
def upstream_role_reader = authorization&.upstream_role_reader
|
|
146
|
+
|
|
147
|
+
def upstream_role_reader=(value)
|
|
148
|
+
authorization&.upstream_role_reader = value
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @deprecated Use `client.authorization.compare_upstream_roles`.
|
|
152
|
+
def compare_upstream_roles = authorization&.compare_upstream_roles || false
|
|
153
|
+
|
|
154
|
+
def compare_upstream_roles=(value)
|
|
155
|
+
authorization&.compare_upstream_roles = value
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# The default client's authorization context, or `nil` when no client
|
|
159
|
+
# has been configured yet.
|
|
160
|
+
#
|
|
161
|
+
# Nil-tolerant on purpose. These delegators exist only for backward
|
|
162
|
+
# compatibility, and the module-level API they replace worked in a
|
|
163
|
+
# process that had never called `Parse.setup` (it kept its own
|
|
164
|
+
# process-local caches). Raising `ConnectionError` from what used to be
|
|
165
|
+
# a plain attribute reader would break configuration code that touches
|
|
166
|
+
# these before setting up a client, and `reset!` is a test helper that
|
|
167
|
+
# must not require a live client to run.
|
|
168
|
+
#
|
|
169
|
+
# @return [Parse::Authorization::Context, nil]
|
|
170
|
+
def authorization
|
|
171
|
+
Parse.client&.authorization
|
|
172
|
+
rescue Parse::Error::ConnectionError
|
|
173
|
+
nil
|
|
174
|
+
end
|
|
129
175
|
|
|
130
176
|
# Configure Atlas Search (uses Parse::MongoDB connection)
|
|
131
177
|
# @param enabled [Boolean] whether to enable Atlas Search (default: true)
|
|
@@ -142,6 +188,12 @@ module Parse
|
|
|
142
188
|
# (seconds). Default: 3600.
|
|
143
189
|
# @param role_cache_ttl [Integer] role-name cache TTL (seconds).
|
|
144
190
|
# Default: 30.
|
|
191
|
+
# @param upstream_role_reader [#roles_for, nil] see
|
|
192
|
+
# {#upstream_role_reader}. Default: unchanged (`nil` unless set
|
|
193
|
+
# separately).
|
|
194
|
+
# @param compare_upstream_roles [Boolean] see
|
|
195
|
+
# {#compare_upstream_roles}. Default: unchanged (`false` unless
|
|
196
|
+
# set separately).
|
|
145
197
|
# @example
|
|
146
198
|
# Parse::AtlasSearch.configure(enabled: true, default_index: "default")
|
|
147
199
|
def configure(enabled: true,
|
|
@@ -149,14 +201,22 @@ module Parse
|
|
|
149
201
|
allow_raw: nil,
|
|
150
202
|
require_session_token: nil,
|
|
151
203
|
session_cache_ttl: nil,
|
|
152
|
-
role_cache_ttl: nil
|
|
204
|
+
role_cache_ttl: nil,
|
|
205
|
+
upstream_role_reader: nil,
|
|
206
|
+
compare_upstream_roles: nil)
|
|
153
207
|
Parse::MongoDB.require_gem!
|
|
154
208
|
@enabled = enabled
|
|
155
209
|
@default_index = default_index
|
|
156
210
|
@allow_raw = allow_raw.nil? ? default_allow_raw : allow_raw
|
|
157
211
|
@require_session_token = require_session_token unless require_session_token.nil?
|
|
158
|
-
|
|
159
|
-
|
|
212
|
+
# Authorization settings belong to the client, not to this module.
|
|
213
|
+
# Forwarded rather than stored so there is exactly one copy.
|
|
214
|
+
authorization&.configure(
|
|
215
|
+
identity_cache_ttl: session_cache_ttl,
|
|
216
|
+
role_cache_ttl: role_cache_ttl,
|
|
217
|
+
upstream_role_reader: upstream_role_reader,
|
|
218
|
+
compare_upstream_roles: compare_upstream_roles,
|
|
219
|
+
)
|
|
160
220
|
IndexManager.clear_cache
|
|
161
221
|
end
|
|
162
222
|
|
|
@@ -194,10 +254,15 @@ module Parse
|
|
|
194
254
|
@default_index = "default"
|
|
195
255
|
@allow_raw = default_allow_raw
|
|
196
256
|
@require_session_token = false
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
257
|
+
authorization&.configure(
|
|
258
|
+
identity_cache_ttl: Parse::Authorization::Context::DEFAULT_IDENTITY_TTL,
|
|
259
|
+
role_cache_ttl: Parse::Authorization::Context::DEFAULT_ROLE_TTL,
|
|
260
|
+
identity_cache: Parse::Authorization::MemoryCache.new,
|
|
261
|
+
role_cache: Parse::Authorization::MemoryCache.new,
|
|
262
|
+
upstream_role_reader: false,
|
|
263
|
+
compare_upstream_roles: false,
|
|
264
|
+
)
|
|
265
|
+
authorization&.upstream_role_reader = nil
|
|
201
266
|
@master_warned = false
|
|
202
267
|
IndexManager.clear_cache
|
|
203
268
|
end
|
|
@@ -497,6 +562,7 @@ module Parse
|
|
|
497
562
|
raw_results = run_atlas_pipeline!(
|
|
498
563
|
collection_name, pipeline, options[:max_time_ms],
|
|
499
564
|
read_preference: read_preference,
|
|
565
|
+
authorizing_client: Parse::ACLScope.client_of(resolution),
|
|
500
566
|
)
|
|
501
567
|
|
|
502
568
|
unless resolution.master?
|
|
@@ -635,6 +701,7 @@ module Parse
|
|
|
635
701
|
facet_results_raw = run_atlas_pipeline!(
|
|
636
702
|
collection_name, facet_pipeline, options[:max_time_ms],
|
|
637
703
|
read_preference: read_preference,
|
|
704
|
+
authorizing_client: Parse::ACLScope.client_of(resolution),
|
|
638
705
|
)
|
|
639
706
|
|
|
640
707
|
# Extract facet results
|
|
@@ -668,6 +735,11 @@ module Parse
|
|
|
668
735
|
search_opts = options.merge(limit: limit, skip: skip_val)
|
|
669
736
|
search_opts[:master] = true if acl[:master]
|
|
670
737
|
search_opts[:read_preference] = read_preference if read_preference
|
|
738
|
+
# Re-thread the client for the same reason as the auth kwargs
|
|
739
|
+
# above: the outer faceted_search popped it in resolve_scope!, so
|
|
740
|
+
# this inner search would otherwise resolve and read as the
|
|
741
|
+
# default application.
|
|
742
|
+
search_opts[:client] = Parse::ACLScope.client_of(resolution) if Parse::ACLScope.client_of(resolution)
|
|
671
743
|
search(collection_name, query, **search_opts).results
|
|
672
744
|
else
|
|
673
745
|
[]
|
|
@@ -686,10 +758,10 @@ module Parse
|
|
|
686
758
|
# `find` / pointerFields / protectedFields / highlight-field
|
|
687
759
|
# checks.
|
|
688
760
|
def search_pipeline!(collection_name, search_stage, resolution:,
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
761
|
+
protected_fields:, pointer_fields:,
|
|
762
|
+
highlight_field: nil, filter: nil, sort: nil,
|
|
763
|
+
skip: 0, limit: 100, max_time_ms: nil,
|
|
764
|
+
read_preference: nil, class_name: nil, raw: false)
|
|
693
765
|
# Backstop the stage-safety check at the shared execution chokepoint
|
|
694
766
|
# so ANY path that runs a $search stage (not just search_with_stage)
|
|
695
767
|
# rejects a non-$search stage / returnStoredSource. The .search and
|
|
@@ -735,6 +807,7 @@ module Parse
|
|
|
735
807
|
# enforcement chain inline below.
|
|
736
808
|
raw_results = run_atlas_pipeline!(
|
|
737
809
|
collection_name, pipeline, max_time_ms, read_preference: read_preference,
|
|
810
|
+
authorizing_client: Parse::ACLScope.client_of(resolution),
|
|
738
811
|
)
|
|
739
812
|
|
|
740
813
|
# Post-fetch enforcement: walk the result rows the same way
|
|
@@ -797,6 +870,10 @@ module Parse
|
|
|
797
870
|
master = options.delete(:master)
|
|
798
871
|
acl_user = options.delete(:acl_user)
|
|
799
872
|
acl_role = options.delete(:acl_role)
|
|
873
|
+
# Consumed like the other auth kwargs so it never reaches the driver,
|
|
874
|
+
# and so `agent.acl_scope_kwargs` can carry the agent's own client
|
|
875
|
+
# into a `$search` the same way it carries the identity.
|
|
876
|
+
scope_client = options.delete(:client)
|
|
800
877
|
|
|
801
878
|
# 4-way mutex. Mirrors Parse::ACLScope.resolve!'s
|
|
802
879
|
# `provided.length > 1` check so an `acl_user:` + `acl_role:`
|
|
@@ -814,28 +891,57 @@ module Parse
|
|
|
814
891
|
"session_token:, master: true, acl_user:, or acl_role:. Pick one."
|
|
815
892
|
end
|
|
816
893
|
|
|
894
|
+
# Resolve against the caller's own client when one was supplied.
|
|
895
|
+
# Atlas Search used to go only through the `Session` shim, which can
|
|
896
|
+
# address nothing but `Parse.client`, so a `$search` issued by a
|
|
897
|
+
# secondary client resolved its token against the wrong application.
|
|
898
|
+
#
|
|
899
|
+
# With no explicit client the RESOLUTION still goes through
|
|
900
|
+
# `Session.resolve` against the default, preserving the historical
|
|
901
|
+
# path, but the Resolution records the default client rather than
|
|
902
|
+
# nil.
|
|
903
|
+
#
|
|
904
|
+
# Recording nil was wrong. This is a public entry point, and the rule
|
|
905
|
+
# is that a public entry point resolves omission to the default once
|
|
906
|
+
# while internal sinks treat nil as unidentified. Leaving it nil here
|
|
907
|
+
# pushed an omission all the way down, so after a second application
|
|
908
|
+
# had been observed every ordinary default-client `$search` was
|
|
909
|
+
# rejected as unidentified.
|
|
910
|
+
auth_client = scope_client || default_authorizing_client
|
|
911
|
+
|
|
817
912
|
if session_token
|
|
818
|
-
resolved
|
|
913
|
+
# Branch on the EXPLICIT client, not the resolved one. With none
|
|
914
|
+
# supplied this must stay on `Session.resolve` (the historical
|
|
915
|
+
# default-client path) while still recording the default on the
|
|
916
|
+
# Resolution below. Branching on `auth_client` routed the ordinary
|
|
917
|
+
# case through a different resolver.
|
|
918
|
+
resolved = if scope_client
|
|
919
|
+
scope_client.authorization.resolve(session_token)
|
|
920
|
+
else
|
|
921
|
+
Session.resolve(session_token)
|
|
922
|
+
end
|
|
819
923
|
return Parse::ACLScope::Resolution.new(
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
924
|
+
mode: :session,
|
|
925
|
+
permission_strings: resolved.permission_strings,
|
|
926
|
+
user_id: resolved.user_id,
|
|
927
|
+
session: resolved,
|
|
928
|
+
client: auth_client,
|
|
929
|
+
)
|
|
825
930
|
end
|
|
826
931
|
|
|
827
932
|
if acl_user
|
|
828
|
-
return Parse::ACLScope.resolve_for_user(acl_user)
|
|
933
|
+
return Parse::ACLScope.resolve_for_user(acl_user, client: auth_client)
|
|
829
934
|
end
|
|
830
935
|
|
|
831
936
|
if acl_role
|
|
832
|
-
return Parse::ACLScope.resolve_for_role(acl_role)
|
|
937
|
+
return Parse::ACLScope.resolve_for_role(acl_role, client: auth_client)
|
|
833
938
|
end
|
|
834
939
|
|
|
835
940
|
if master == true
|
|
836
941
|
return Parse::ACLScope::Resolution.new(
|
|
837
|
-
|
|
838
|
-
|
|
942
|
+
mode: :master, permission_strings: nil, user_id: nil, session: nil,
|
|
943
|
+
client: auth_client,
|
|
944
|
+
)
|
|
839
945
|
end
|
|
840
946
|
|
|
841
947
|
if @require_session_token == true
|
|
@@ -854,9 +960,20 @@ module Parse
|
|
|
854
960
|
permission_strings: anonymous.permission_strings,
|
|
855
961
|
user_id: nil,
|
|
856
962
|
session: anonymous,
|
|
963
|
+
client: auth_client,
|
|
857
964
|
)
|
|
858
965
|
end
|
|
859
966
|
|
|
967
|
+
# @!visibility private
|
|
968
|
+
# The default Parse client, or nil when none is configured. Never
|
|
969
|
+
# raises and never constructs one: `Parse.client` does both.
|
|
970
|
+
def default_authorizing_client
|
|
971
|
+
return nil unless Parse::Client.client?
|
|
972
|
+
Parse.client
|
|
973
|
+
rescue StandardError
|
|
974
|
+
nil
|
|
975
|
+
end
|
|
976
|
+
|
|
860
977
|
# CLP `find` boundary check. Master-mode skips; for every other
|
|
861
978
|
# scope, refuse the call when the resolved claim set can't
|
|
862
979
|
# `find` on the collection. Mirrors what Parse::MongoDB.aggregate
|
|
@@ -940,10 +1057,13 @@ module Parse
|
|
|
940
1057
|
# helper {Parse::MongoDB.aggregate} uses so the kwarg semantics
|
|
941
1058
|
# are identical on both paths (invalid values warn and route to
|
|
942
1059
|
# primary; nil = no override).
|
|
943
|
-
def run_atlas_pipeline!(collection_name, pipeline, max_time_ms = nil, read_preference: nil
|
|
1060
|
+
def run_atlas_pipeline!(collection_name, pipeline, max_time_ms = nil, read_preference: nil,
|
|
1061
|
+
authorizing_client: nil)
|
|
944
1062
|
agg_opts = {}
|
|
945
1063
|
agg_opts[:max_time_ms] = max_time_ms if max_time_ms
|
|
946
|
-
|
|
1064
|
+
# Atlas Search does not go through Parse::MongoDB.aggregate, so this
|
|
1065
|
+
# is the only place its reads meet the binding guard.
|
|
1066
|
+
coll = Parse::MongoDB.collection(collection_name, authorizing_client: authorizing_client)
|
|
947
1067
|
if (mode = Parse::MongoDB.send(:normalize_read_preference, read_preference))
|
|
948
1068
|
coll = coll.with(read: { mode: mode })
|
|
949
1069
|
end
|
|
@@ -1147,10 +1267,11 @@ module Parse
|
|
|
1147
1267
|
@default_index = "default"
|
|
1148
1268
|
@allow_raw = nil
|
|
1149
1269
|
@require_session_token = false
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1270
|
+
# No authorization ivars here anymore. The identity and role caches, their
|
|
1271
|
+
# TTLs, and the upstream reader live on each client's
|
|
1272
|
+
# Parse::Authorization::Context and are initialized there, so this module
|
|
1273
|
+
# cannot hold a second, divergent copy. Initializing them at load time
|
|
1274
|
+
# would also require a configured client before one exists.
|
|
1154
1275
|
@master_warned = false
|
|
1155
1276
|
end
|
|
1156
1277
|
end
|