parse-stack-next 5.5.3 → 5.5.5

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.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -4
  3. data/README.md +26 -13
  4. data/bin/parse-console +9 -1
  5. data/docs/TEST_SERVER.md +115 -238
  6. data/docs/mcp_guide.md +1 -1
  7. data/docs/mongodb_index_optimization_guide.md +3 -2
  8. data/docs/usage_guide.md +1 -1
  9. data/docs/yard-template/default/fulldoc/html/css/common.css +52 -9
  10. data/docs/yard-template/default/fulldoc/html/css/full_list.css +40 -13
  11. data/lib/parse/agent/constraint_translator.rb +18 -18
  12. data/lib/parse/agent/errors.rb +29 -7
  13. data/lib/parse/agent/metadata_dsl.rb +6 -6
  14. data/lib/parse/agent/tools.rb +250 -59
  15. data/lib/parse/agent.rb +42 -30
  16. data/lib/parse/api/aggregate.rb +3 -3
  17. data/lib/parse/api/cloud_functions.rb +19 -10
  18. data/lib/parse/api/objects.rb +8 -8
  19. data/lib/parse/api/users.rb +9 -9
  20. data/lib/parse/atlas_search/session.rb +34 -34
  21. data/lib/parse/atlas_search.rb +243 -110
  22. data/lib/parse/client/body_builder.rb +10 -10
  23. data/lib/parse/client/logging.rb +5 -2
  24. data/lib/parse/client/profiling.rb +5 -2
  25. data/lib/parse/client/protocol.rb +1 -1
  26. data/lib/parse/client/url_redaction.rb +94 -0
  27. data/lib/parse/client.rb +43 -28
  28. data/lib/parse/embeddings/image_fetch.rb +6 -1
  29. data/lib/parse/embeddings/voyage.rb +16 -17
  30. data/lib/parse/live_query/client.rb +7 -7
  31. data/lib/parse/live_query/subscription.rb +1 -1
  32. data/lib/parse/lock.rb +1 -1
  33. data/lib/parse/lock_backend.rb +118 -2
  34. data/lib/parse/model/acl.rb +24 -24
  35. data/lib/parse/model/classes/job_schedule.rb +8 -8
  36. data/lib/parse/model/classes/job_status.rb +9 -9
  37. data/lib/parse/model/classes/role.rb +49 -49
  38. data/lib/parse/model/classes/session.rb +2 -2
  39. data/lib/parse/model/classes/user.rb +66 -66
  40. data/lib/parse/model/core/builder.rb +7 -7
  41. data/lib/parse/model/core/create_lock.rb +1 -1
  42. data/lib/parse/model/core/properties.rb +4 -4
  43. data/lib/parse/model/file.rb +57 -16
  44. data/lib/parse/model/model.rb +19 -19
  45. data/lib/parse/model/object.rb +38 -38
  46. data/lib/parse/model/pointer.rb +4 -4
  47. data/lib/parse/model/push.rb +5 -5
  48. data/lib/parse/mongodb.rb +84 -26
  49. data/lib/parse/pipeline_security.rb +2 -2
  50. data/lib/parse/query/constraints.rb +38 -38
  51. data/lib/parse/query.rb +151 -75
  52. data/lib/parse/retrieval/reranker/cohere.rb +30 -0
  53. data/lib/parse/schema.rb +1 -1
  54. data/lib/parse/stack/version.rb +1 -1
  55. data/lib/parse/stack.rb +23 -10
  56. data/lib/parse/two_factor_auth/user_extension.rb +25 -25
  57. data/lib/parse/webhooks/payload.rb +35 -35
  58. data/lib/parse/webhooks/registration.rb +2 -2
  59. data/lib/parse/webhooks/replay_protection.rb +16 -16
  60. data/lib/parse/webhooks.rb +11 -11
  61. data/parse-stack-next.gemspec +19 -1
  62. metadata +2 -38
  63. data/.bundle/config +0 -5
  64. data/.env.sample +0 -138
  65. data/.env.test +0 -10
  66. data/.github/ISSUE_TEMPLATE/bug_report.yml +0 -105
  67. data/.github/ISSUE_TEMPLATE/feature_request.yml +0 -67
  68. data/.github/dependabot.yml +0 -13
  69. data/.github/workflows/codeql.yml +0 -44
  70. data/.github/workflows/docs.yml +0 -39
  71. data/.github/workflows/release.yml +0 -43
  72. data/.github/workflows/ruby.yml +0 -38
  73. data/.gitignore +0 -56
  74. data/.ruby-version +0 -1
  75. data/.solargraph.yml +0 -22
  76. data/.vscode/settings.json +0 -3
  77. data/.yardopts +0 -19
  78. data/Gemfile +0 -43
  79. data/Gemfile.lock +0 -198
  80. data/Makefile +0 -63
  81. data/Rakefile +0 -825
  82. data/config/parse-config.json +0 -12
  83. data/scripts/debug-ips.js +0 -35
  84. data/scripts/docker/Dockerfile.parse +0 -17
  85. data/scripts/docker/atlas-init.js +0 -284
  86. data/scripts/docker/docker-compose.atlas.yml +0 -80
  87. data/scripts/docker/docker-compose.test.yml +0 -159
  88. data/scripts/docker/docker-compose.verifyemail.yml +0 -4
  89. data/scripts/docker/mongo-init.js +0 -21
  90. data/scripts/docker/preflight.sh +0 -76
  91. data/scripts/eval_mcp_with_lm_studio.rb +0 -274
  92. data/scripts/start-parse.sh +0 -154
  93. data/scripts/start_mcp_server.rb +0 -78
  94. data/scripts/test_server_connection.rb +0 -82
  95. data/scripts/vector_prototype/create_vector_index.js +0 -105
  96. data/scripts/vector_prototype/fetch_embeddings.py +0 -241
  97. data/scripts/vector_prototype/fixture_manifest.json +0 -9
  98. data/scripts/vector_prototype/query_prototype.rb +0 -84
  99. data/scripts/vector_prototype/run.sh +0 -34
@@ -67,28 +67,28 @@ module Parse
67
67
  attr_accessor :query, :log, :objects
68
68
  attr_accessor :original, :update, :raw
69
69
  # @!attribute [rw] event
70
- # The LiveQuery event type for an +afterEvent+ trigger -- one of
71
- # +"create"+, +"enter"+, +"update"+, +"leave"+, or +"delete"+ -- or
72
- # +"connect"+ for a +beforeConnect+ trigger. +nil+ for every non-
70
+ # The LiveQuery event type for an `afterEvent` trigger -- one of
71
+ # `"create"`, `"enter"`, `"update"`, `"leave"`, or `"delete"` -- or
72
+ # `"connect"` for a `beforeConnect` trigger. `nil` for every non-
73
73
  # LiveQuery trigger. See {#after_event?} / {#before_connect?}.
74
74
  # @return [String, nil]
75
75
  # @!attribute [rw] clients
76
- # Connection-global metadata sent on the LiveQuery +beforeConnect+ /
77
- # +afterEvent+ triggers: the number of currently-connected LiveQuery
78
- # clients. +nil+ for non-LiveQuery triggers.
76
+ # Connection-global metadata sent on the LiveQuery `beforeConnect` /
77
+ # `afterEvent` triggers: the number of currently-connected LiveQuery
78
+ # clients. `nil` for non-LiveQuery triggers.
79
79
  # @return [Integer, nil]
80
80
  # @!attribute [rw] subscriptions
81
- # Connection-global metadata sent on the LiveQuery +beforeConnect+ /
82
- # +afterEvent+ triggers: the number of active subscriptions. +nil+ for
81
+ # Connection-global metadata sent on the LiveQuery `beforeConnect` /
82
+ # `afterEvent` triggers: the number of active subscriptions. `nil` for
83
83
  # non-LiveQuery triggers.
84
84
  # @return [Integer, nil]
85
85
  attr_accessor :event, :clients, :subscriptions
86
86
  # @!attribute [rw] context
87
87
  # The caller-supplied context object threaded from the originating REST
88
- # write or cloud-function call via the +X-Parse-Cloud-Context+ header.
89
- # Parse Server includes this as a top-level +context+ key in trigger
88
+ # write or cloud-function call via the `X-Parse-Cloud-Context` header.
89
+ # Parse Server includes this as a top-level `context` key in trigger
90
90
  # payloads (beforeSave/afterSave/etc.). Returns a Hash when present, or
91
- # +nil+ when the originating request carried no context.
91
+ # `nil` when the originating request carried no context.
92
92
  # @return [Hash, nil]
93
93
  attr_accessor :context
94
94
  # @!attribute [r] session_token
@@ -96,7 +96,7 @@ module Parse
96
96
  # webhook payload (`user.sessionToken`) before credentials are scrubbed
97
97
  # from {#user} / {#object} / {#original} / {#update}. Present only when
98
98
  # the originating request was made by a logged-in user -- a master-key
99
- # request carries no user and no token, so this is +nil+. It is
99
+ # request carries no user and no token, so this is `nil`. It is
100
100
  # intentionally NOT one of {ATTRIBUTES}, so it never appears in
101
101
  # {#as_json} or in the redacted request log. Reach for it (or the
102
102
  # higher-level {#user_client} / {#user_agent}) only when a handler
@@ -232,7 +232,7 @@ module Parse
232
232
  ].freeze
233
233
 
234
234
  # @!visibility private
235
- # Returns a copy of +obj+ with only +WEBHOOK_TRIGGER_CREDENTIAL_KEYS+
235
+ # Returns a copy of `obj` with only `WEBHOOK_TRIGGER_CREDENTIAL_KEYS`
236
236
  # removed. Operates on string and symbol keys (Parse Server uses camelCase
237
237
  # strings on the wire; downstream code may have already symbolized).
238
238
  # Pass-through for non-Hash input.
@@ -274,7 +274,7 @@ module Parse
274
274
  end
275
275
 
276
276
  # @!visibility private
277
- # Returns a copy of +obj+ with the model's declared `:vector`
277
+ # Returns a copy of `obj` with the model's declared `:vector`
278
278
  # columns removed. Embeddings are large dense float arrays that leak
279
279
  # ML signal; a webhook handler has no reason to receive them, and
280
280
  # leaving them in bloats logs and any object a handler re-persists.
@@ -302,10 +302,10 @@ module Parse
302
302
  end
303
303
 
304
304
  # @!visibility private
305
- # Pulls the caller's session token out of the (unscrubbed) +user+ hash.
306
- # Parse Server sends it as the camelCase string key +sessionToken+; this
305
+ # Pulls the caller's session token out of the (unscrubbed) `user` hash.
306
+ # Parse Server sends it as the camelCase string key `sessionToken`; this
307
307
  # tolerates a symbol key and the snake_case form too, mirroring the
308
- # leniency in +scrub_credentials+. Returns +nil+ for a blank token or a
308
+ # leniency in `scrub_credentials`. Returns `nil` for a blank token or a
309
309
  # non-Hash / absent user (a master-key request has no user).
310
310
  def self.extract_session_token(user_hash)
311
311
  return nil unless user_hash.is_a?(Hash)
@@ -365,14 +365,14 @@ module Parse
365
365
 
366
366
  # An opt-in, user-scoped {Parse::Client} for acting on the server as the
367
367
  # webhook's calling user. It mirrors the default client's connection
368
- # settings (+server_url+, +application_id+, +api_key+) but carries NO
368
+ # settings (`server_url`, `application_id`, `api_key`) but carries NO
369
369
  # master key and BINDS the caller's {#session_token}, so every request it
370
370
  # makes -- with no further ceremony -- is authorized by Parse Server as
371
- # that user: ACL, CLP and +protectedFields+ are all enforced. (A
371
+ # that user: ACL, CLP and `protectedFields` are all enforced. (A
372
372
  # `Parse.with_session` block still overrides the bound token if you need
373
373
  # to act as someone else within a call.) Memoized per payload, since each
374
374
  # webhook delivery carries a distinct token.
375
- # @return [Parse::Client, nil] +nil+ when the payload carried no token.
375
+ # @return [Parse::Client, nil] `nil` when the payload carried no token.
376
376
  def user_client
377
377
  return nil if @session_token.nil?
378
378
  @user_client ||= Parse::Client.client.become(@session_token)
@@ -380,15 +380,15 @@ module Parse
380
380
 
381
381
  # An opt-in, non-master {Parse::Agent} scoped to the webhook caller's
382
382
  # session token. Because its client has no master key and it is built
383
- # with a non-empty +session_token:+, the agent runs in CLIENT MODE:
383
+ # with a non-empty `session_token:`, the agent runs in CLIENT MODE:
384
384
  # every tool/query routes through a path Parse Server (or the SDK's own
385
385
  # ACL/CLP enforcement layer) authorizes as the calling user, with no
386
386
  # master-key fallback to silently bypass row-level security. This is the
387
387
  # handle to use when a handler should read or act strictly within the
388
388
  # caller's permissions. Additional agent options (e.g.
389
- # +permissions: :readwrite+) may be passed through.
389
+ # `permissions: :readwrite`) may be passed through.
390
390
  # @param opts [Hash] extra keyword args forwarded to {Parse::Agent#initialize}.
391
- # @return [Parse::Agent, nil] +nil+ when the payload carried no token.
391
+ # @return [Parse::Agent, nil] `nil` when the payload carried no token.
392
392
  def user_agent(**opts)
393
393
  return nil if @session_token.nil?
394
394
  require_relative "../agent" unless defined?(Parse::Agent)
@@ -462,11 +462,11 @@ module Parse
462
462
 
463
463
  # true if this is a beforeLogin webhook trigger request.
464
464
  #
465
- # NOTE: a +beforeLogin+ payload carries the user being authenticated as
466
- # {#object} / {#parse_object} (a +_User+), NOT as {#user} -- the caller is
467
- # not yet authenticated when the trigger fires, so {#user} is +nil+. (By
468
- # +afterLogin+ both are populated and equal.) Reach for {#parse_object} to
469
- # inspect the logging-in user during +beforeLogin+.
465
+ # NOTE: a `beforeLogin` payload carries the user being authenticated as
466
+ # {#object} / {#parse_object} (a `_User`), NOT as {#user} -- the caller is
467
+ # not yet authenticated when the trigger fires, so {#user} is `nil`. (By
468
+ # `afterLogin` both are populated and equal.) Reach for {#parse_object} to
469
+ # inspect the logging-in user during `beforeLogin`.
470
470
  def before_login?
471
471
  trigger? && @trigger_name.to_sym == :beforeLogin
472
472
  end
@@ -477,19 +477,19 @@ module Parse
477
477
  end
478
478
 
479
479
  # true if this is a afterLogout webhook trigger request. The logged-out
480
- # session is carried as {#object} / {#parse_object} (a +_Session+).
480
+ # session is carried as {#object} / {#parse_object} (a `_Session`).
481
481
  def after_logout?
482
482
  trigger? && @trigger_name.to_sym == :afterLogout
483
483
  end
484
484
 
485
485
  # true if this is a beforePasswordResetRequest webhook trigger request.
486
- # The target user is carried as {#object} / {#parse_object} (a +_User+).
486
+ # The target user is carried as {#object} / {#parse_object} (a `_User`).
487
487
  def before_password_reset_request?
488
488
  trigger? && @trigger_name.to_sym == :beforePasswordResetRequest
489
489
  end
490
490
 
491
491
  # true if this is a LiveQuery beforeConnect webhook trigger request.
492
- # Connection-global: carries no {#object}; the className is the +@Connect+
492
+ # Connection-global: carries no {#object}; the className is the `@Connect`
493
493
  # sentinel and the caller's token (if any) is in {#session_token}.
494
494
  def before_connect?
495
495
  trigger? && @trigger_name.to_sym == :beforeConnect
@@ -510,10 +510,10 @@ module Parse
510
510
 
511
511
  # true if this is one of the authentication-side triggers
512
512
  # (beforeLogin / afterLogin / afterLogout / beforePasswordResetRequest).
513
- # These carry a +_User+ / +_Session+ as {#object} but are NOT object
513
+ # These carry a `_User` / `_Session` as {#object} but are NOT object
514
514
  # save/delete triggers: no ActiveModel save/create/destroy callbacks run
515
515
  # for them, and Parse Server ignores the response body (the only way to
516
- # affect a +before*+ one is to deny it -- see the webhook router).
516
+ # affect a `before*` one is to deny it -- see the webhook router).
517
517
  def auth_trigger?
518
518
  before_login? || after_login? || after_logout? || before_password_reset_request?
519
519
  end
@@ -521,7 +521,7 @@ module Parse
521
521
  # true if this is one of the LiveQuery triggers (beforeConnect /
522
522
  # beforeSubscribe / afterEvent). Parse Server delivers these over an HTTP
523
523
  # webhook only in a co-located single-process LiveQuery setup;
524
- # +beforeConnect+ in particular carries a live client and is effectively
524
+ # `beforeConnect` in particular carries a live client and is effectively
525
525
  # in-process-only. See the webhooks guide.
526
526
  def live_query_trigger?
527
527
  before_connect? || before_subscribe? || after_event?
@@ -560,7 +560,7 @@ module Parse
560
560
  end
561
561
 
562
562
  # @!visibility private
563
- # Returns +true+ when +@object+/+@original+ contain a className that
563
+ # Returns `true` when `@object`/`@original` contain a className that
564
564
  # disagrees with the trigger's expected class. Used to skip building
565
565
  # a typed object when the payload was clearly forged or routed
566
566
  # incorrectly.
@@ -24,8 +24,8 @@ module Parse
24
24
  # Parse Server. Rejects non-http(s) schemes, embedded userinfo, and
25
25
  # hostnames that resolve to loopback, link-local, RFC1918, CGNAT,
26
26
  # multicast, or cloud-metadata addresses (covered by
27
- # +Parse::File::BLOCKED_CIDRS+). Without these checks an attacker who
28
- # can reach +register_webhook!+ could redirect Parse Server's trigger
27
+ # `Parse::File::BLOCKED_CIDRS`). Without these checks an attacker who
28
+ # can reach `register_webhook!` could redirect Parse Server's trigger
29
29
  # POSTs to an internal host (e.g. the cloud metadata service) and
30
30
  # exfiltrate request bodies. Returns the input URL unchanged on
31
31
  # success.
@@ -11,8 +11,8 @@ module Parse
11
11
  # NEW-EXT-4: webhook freshness and replay protection.
12
12
  #
13
13
  # Parse Server's default webhook delivery is authenticated only by the
14
- # static +X-Parse-Webhook-Key+ header. A captured POST is therefore
15
- # indefinitely replayable -- a Ruby-initiated save bearing an +_RB_+
14
+ # static `X-Parse-Webhook-Key` header. A captured POST is therefore
15
+ # indefinitely replayable -- a Ruby-initiated save bearing an `_RB_`
16
16
  # request id will continue to suppress server-side after_* callbacks
17
17
  # every time it is replayed, and a generic trigger payload can be
18
18
  # delivered repeatedly to fire double-charges or other side effects.
@@ -20,23 +20,23 @@ module Parse
20
20
  # This module adds two layers on top of the existing static-key check:
21
21
  #
22
22
  # 1. **Always-on body+request-id dedup.** A bounded LRU records a
23
- # SHA-256 of +(request_id || "")+ joined with the request body. A
24
- # duplicate seen within +replay_window_seconds+ is rejected with
25
- # +"Webhook replay detected."+. Cooperation with Parse Server is not
23
+ # SHA-256 of `(request_id || "")` joined with the request body. A
24
+ # duplicate seen within `replay_window_seconds` is rejected with
25
+ # `"Webhook replay detected."`. Cooperation with Parse Server is not
26
26
  # required; this protects against in-window replays only, but those
27
27
  # are the cheapest attack to mount (proxy retries, captured fast
28
28
  # loops, retransmits).
29
29
  #
30
- # 2. **Opt-in HMAC freshness verification.** When a +signing_secret+ is
30
+ # 2. **Opt-in HMAC freshness verification.** When a `signing_secret` is
31
31
  # configured (programmatically or via
32
- # +PARSE_WEBHOOK_SIGNING_SECRET+) the dispatcher requires two extra
32
+ # `PARSE_WEBHOOK_SIGNING_SECRET`) the dispatcher requires two extra
33
33
  # headers on every request:
34
34
  #
35
- # * +X-Parse-Webhook-Timestamp+ -- decimal Unix epoch seconds.
36
- # * +X-Parse-Webhook-Signature+ -- hex-encoded HMAC-SHA256 of the
37
- # bytes +"#{timestamp}.#{body}"+ keyed with the signing secret.
35
+ # * `X-Parse-Webhook-Timestamp` -- decimal Unix epoch seconds.
36
+ # * `X-Parse-Webhook-Signature` -- hex-encoded HMAC-SHA256 of the
37
+ # bytes `"#{timestamp}.#{body}"` keyed with the signing secret.
38
38
  #
39
- # Requests outside +signing_max_skew_seconds+ (default 300) or with
39
+ # Requests outside `signing_max_skew_seconds` (default 300) or with
40
40
  # an invalid signature are rejected. Once enabled, this gives full
41
41
  # binding between the body and the time of delivery and closes the
42
42
  # replay window beyond the freshness skew.
@@ -61,9 +61,9 @@ module Parse
61
61
  attr_writer :signing_secret, :signing_max_skew_seconds,
62
62
  :replay_window_seconds, :replay_cache_size
63
63
 
64
- # Shared HMAC secret used to verify +X-Parse-Webhook-Signature+.
64
+ # Shared HMAC secret used to verify `X-Parse-Webhook-Signature`.
65
65
  # When nil/empty, signature verification is skipped (layer 1 still
66
- # applies). Defaults to +ENV["PARSE_WEBHOOK_SIGNING_SECRET"]+.
66
+ # applies). Defaults to `ENV["PARSE_WEBHOOK_SIGNING_SECRET"]`.
67
67
  def signing_secret
68
68
  return @signing_secret if defined?(@signing_secret) && !@signing_secret.nil?
69
69
  ENV["PARSE_WEBHOOK_SIGNING_SECRET"]
@@ -71,12 +71,12 @@ module Parse
71
71
 
72
72
  # Maximum allowed clock skew (in seconds) between the timestamp
73
73
  # header and the receiver. Requests outside this window are
74
- # rejected as stale when +signing_secret+ is set.
74
+ # rejected as stale when `signing_secret` is set.
75
75
  def signing_max_skew_seconds
76
76
  @signing_max_skew_seconds || DEFAULT_MAX_SKEW
77
77
  end
78
78
 
79
- # How long a +(request_id, body)+ digest stays in the dedup cache.
79
+ # How long a `(request_id, body)` digest stays in the dedup cache.
80
80
  # Duplicates seen within this window are rejected.
81
81
  def replay_window_seconds
82
82
  @replay_window_seconds || DEFAULT_REPLAY_WINDOW
@@ -112,7 +112,7 @@ module Parse
112
112
  # @!visibility private
113
113
  # Returns nil when the request passes both replay and signature
114
114
  # checks; otherwise returns a short error string suitable for the
115
- # webhook error response. The headers come from +env+ so this
115
+ # webhook error response. The headers come from `env` so this
116
116
  # works with any Rack request.
117
117
  def verify!(env, body_str, request_id)
118
118
  secret = signing_secret
@@ -85,7 +85,7 @@ module Parse
85
85
  class ResponseError < StandardError; end
86
86
 
87
87
  # The authentication-side triggers (local underscore form). These carry a
88
- # +_User+ / +_Session+ as the payload object but are NOT object save/delete
88
+ # `_User` / `_Session` as the payload object but are NOT object save/delete
89
89
  # triggers: the router runs no ActiveModel save/create/destroy callbacks for
90
90
  # them, and Parse Server ignores their response body.
91
91
  AUTH_TRIGGERS = %i[
@@ -98,18 +98,18 @@ module Parse
98
98
  LIVE_QUERY_TRIGGERS = %i[before_connect before_subscribe after_event].freeze
99
99
 
100
100
  # Every trigger whose payload is not an object save/delete/find shape.
101
- # Parse Server's webhook response handler resolves +{}+ for all of these
101
+ # Parse Server's webhook response handler resolves `{}` for all of these
102
102
  # (the body is ignored), so the router normalizes their handler result to a
103
103
  # success no-op rather than serializing a returned object into the response.
104
104
  NON_OBJECT_TRIGGERS = (AUTH_TRIGGERS + LIVE_QUERY_TRIGGERS).freeze
105
105
 
106
- # The +before*+ subset of {NON_OBJECT_TRIGGERS} for which a handler can DENY
107
- # the operation. Parse Server only treats an +{error}+ response as a
108
- # rejection -- a +{success:false}+ body resolves and lets the login /
109
- # connect / subscribe / reset proceed. So, mirroring the +before_save+
110
- # convention, the router converts a +false+ return from one of these into a
111
- # {ResponseError} (which serializes to +{error}+). +error!+ works for any
112
- # trigger; the +after*+ variants fire after the fact and cannot undo it.
106
+ # The `before*` subset of {NON_OBJECT_TRIGGERS} for which a handler can DENY
107
+ # the operation. Parse Server only treats an `{error}` response as a
108
+ # rejection -- a `{success:false}` body resolves and lets the login /
109
+ # connect / subscribe / reset proceed. So, mirroring the `before_save`
110
+ # convention, the router converts a `false` return from one of these into a
111
+ # {ResponseError} (which serializes to `{error}`). `error!` works for any
112
+ # trigger; the `after*` variants fire after the fact and cannot undo it.
113
113
  REJECTABLE_NON_OBJECT_TRIGGERS = %i[
114
114
  before_login before_password_reset_request before_connect before_subscribe
115
115
  ].freeze
@@ -607,9 +607,9 @@ module Parse
607
607
  # skips the DNS resolution and private/internal CIDR refusal. Other
608
608
  # checks (scheme, userinfo, host presence) still apply. Intended for
609
609
  # integration tests that register webhooks at Docker bridge hosts
610
- # (e.g. +host.docker.internal+) which only resolve from inside the
610
+ # (e.g. `host.docker.internal`) which only resolve from inside the
611
611
  # Parse Server container. May also be enabled via
612
- # +PARSE_WEBHOOK_ALLOW_PRIVATE_URLS=true+. Do not enable in
612
+ # `PARSE_WEBHOOK_ALLOW_PRIVATE_URLS=true`. Do not enable in
613
613
  # production: the resolution guard is what blocks attacker-driven
614
614
  # webhook redirection to internal hosts.
615
615
  # @return [Boolean]
@@ -23,7 +23,25 @@ Gem::Specification.new do |spec|
23
23
  "rubygems_mfa_required" => "true",
24
24
  }
25
25
 
26
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ # Ship only what an SDK consumer needs: the library, executables, the
27
+ # rendered guides + copy-paste examples, the README banner asset, and the
28
+ # standard metadata files. Everything else that is tracked purely for
29
+ # development — .github/, .vscode/, .bundle/, .env.*, scripts/, config/,
30
+ # Makefile, Rakefile, Gemfile(.lock), and dotfiles — is intentionally
31
+ # excluded so ~1MB of packaging noise isn't shipped to every install.
32
+ spec.files = `git ls-files -z`.split("\x0").select do |f|
33
+ f.start_with?("lib/", "bin/", "docs/", "examples/", "assets/") ||
34
+ %w[
35
+ README.md
36
+ CHANGELOG.md
37
+ LICENSE.txt
38
+ SECURITY.md
39
+ parse-stack-next.gemspec
40
+ ].include?(f)
41
+ end.reject do |f|
42
+ # Internal dev docs that live under docs/ but aren't consumer-facing.
43
+ f == "docs/client_sdk_todo.md"
44
+ end
27
45
  spec.bindir = "bin"
28
46
  spec.executables = ["parse-console"] #spec.files.grep(%r{^bin/pstack/}) { |f| File.basename(f) }
29
47
  spec.require_paths = ["lib"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parse-stack-next
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.3
4
+ version: 5.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Curtin
@@ -208,28 +208,9 @@ executables:
208
208
  extensions: []
209
209
  extra_rdoc_files: []
210
210
  files:
211
- - ".bundle/config"
212
- - ".env.sample"
213
- - ".env.test"
214
- - ".github/ISSUE_TEMPLATE/bug_report.yml"
215
- - ".github/ISSUE_TEMPLATE/feature_request.yml"
216
- - ".github/dependabot.yml"
217
- - ".github/workflows/codeql.yml"
218
- - ".github/workflows/docs.yml"
219
- - ".github/workflows/release.yml"
220
- - ".github/workflows/ruby.yml"
221
- - ".gitignore"
222
- - ".ruby-version"
223
- - ".solargraph.yml"
224
- - ".vscode/settings.json"
225
- - ".yardopts"
226
211
  - CHANGELOG.md
227
- - Gemfile
228
- - Gemfile.lock
229
212
  - LICENSE.txt
230
- - Makefile
231
213
  - README.md
232
- - Rakefile
233
214
  - SECURITY.md
234
215
  - assets/parse-stack-next-avatar.png
235
216
  - assets/parse-stack-next-avatar.svg
@@ -240,7 +221,6 @@ files:
240
221
  - bin/parse-console
241
222
  - bin/server
242
223
  - bin/setup
243
- - config/parse-config.json
244
224
  - docs/TEST_SERVER.md
245
225
  - docs/_config.yml
246
226
  - docs/acl_clp_guide.md
@@ -316,6 +296,7 @@ files:
316
296
  - lib/parse/client/protocol.rb
317
297
  - lib/parse/client/request.rb
318
298
  - lib/parse/client/response.rb
299
+ - lib/parse/client/url_redaction.rb
319
300
  - lib/parse/clp_scope.rb
320
301
  - lib/parse/console.rb
321
302
  - lib/parse/embeddings.rb
@@ -438,23 +419,6 @@ files:
438
419
  - lib/parse/webhooks/replay_protection.rb
439
420
  - lib/parse/webhooks/trigger_audit.rb
440
421
  - parse-stack-next.gemspec
441
- - scripts/debug-ips.js
442
- - scripts/docker/Dockerfile.parse
443
- - scripts/docker/atlas-init.js
444
- - scripts/docker/docker-compose.atlas.yml
445
- - scripts/docker/docker-compose.test.yml
446
- - scripts/docker/docker-compose.verifyemail.yml
447
- - scripts/docker/mongo-init.js
448
- - scripts/docker/preflight.sh
449
- - scripts/eval_mcp_with_lm_studio.rb
450
- - scripts/start-parse.sh
451
- - scripts/start_mcp_server.rb
452
- - scripts/test_server_connection.rb
453
- - scripts/vector_prototype/create_vector_index.js
454
- - scripts/vector_prototype/fetch_embeddings.py
455
- - scripts/vector_prototype/fixture_manifest.json
456
- - scripts/vector_prototype/query_prototype.rb
457
- - scripts/vector_prototype/run.sh
458
422
  homepage: https://github.com/neurosynq/parse-stack-next
459
423
  licenses:
460
424
  - MIT
data/.bundle/config DELETED
@@ -1,5 +0,0 @@
1
- ---
2
- BUNDLE_FORCE_RUBY_PLATFORM: "true"
3
- BUNDLE_FROZEN: "false"
4
- BUNDLE_PATH: "/home/runner/work/parse-stack-next/parse-stack-next/vendor/bundle"
5
- BUNDLE_DEPLOYMENT: "true"
data/.env.sample DELETED
@@ -1,138 +0,0 @@
1
- # Sample environment configuration for parse-stack.
2
- #
3
- # Copy to `.env` and fill in real values. `.env` is gitignored;
4
- # this file (`.env.sample`) is committed as the reference.
5
- #
6
- # Loaded automatically by:
7
- # - `ruby -rdotenv/load -Ilib:test path/to/test.rb`
8
- # - Anything that requires `dotenv` at boot
9
- # Or pass values inline:
10
- # LLM_PROVIDER=openai LLM_API_KEY=sk-... bundle exec rake test:foo
11
-
12
- # ===========================================================================
13
- # Test harness
14
- # ===========================================================================
15
-
16
- # Routes the test suite at the Docker Compose Parse Server + MongoDB defined
17
- # in scripts/docker/docker-compose.test.yml. Unset for in-process unit tests.
18
- PARSE_TEST_USE_DOCKER='true'
19
-
20
- # ===========================================================================
21
- # Parse client (test fixtures + Rake tasks that boot a Parse client)
22
- #
23
- # Defaults below match scripts/docker/docker-compose.test.yml.
24
- # Override for testing against a different Parse Server instance.
25
- # ===========================================================================
26
-
27
- PARSE_SERVER_URL=http://localhost:2337/parse
28
- PARSE_APP_ID=myAppId
29
- PARSE_API_KEY=myApiKey
30
- PARSE_MASTER_KEY=myMasterKey
31
-
32
- # Optional client tuning (read by Parse::Client.new):
33
- # PARSE_OPEN_TIMEOUT=5
34
- # PARSE_TIMEOUT=30
35
- # PARSE_REQUIRE_HTTPS=true
36
-
37
- # Optional service URLs (only if you split webhooks/hooks endpoints):
38
- # PARSE_LIVE_QUERY_URL=
39
- # HOOKS_URL=
40
-
41
- # ===========================================================================
42
- # Test harness — uses an ISOLATED stack (not the values above)
43
- #
44
- # The integration test suite does NOT connect with the defaults above. It runs
45
- # on a deliberately isolated Docker stack — a private 29xxx host-port block, a
46
- # dedicated Compose project `psnext-it`, and the `parse_stack_next_it` database
47
- # — so it never collides with another Parse system on the same host. The full
48
- # value set is listed in `.env.test` (a committed reference; nothing auto-loads
49
- # it — source it or export the vars). The full port map and override variables
50
- # are documented in the "Isolated test environment" section of CLAUDE.md.
51
- # ===========================================================================
52
-
53
- # ===========================================================================
54
- # Webhooks
55
- # ===========================================================================
56
-
57
- # Required for the Parse::Webhooks Rack endpoint to accept calls.
58
- # Without this, the endpoint fails closed (4.0.0+ behavior).
59
- # PARSE_WEBHOOK_KEY=
60
- # PARSE_SERVER_WEBHOOK_KEY=
61
- # PARSE_WEBHOOK_ALLOW_UNAUTHENTICATED=false
62
-
63
- # ===========================================================================
64
- # MCP Server
65
- # ===========================================================================
66
-
67
- # Required dual-gate for the standalone MCP server. Both this AND
68
- # `Parse.mcp_server_enabled = true` (in code) are required before
69
- # Parse::Agent.enable_mcp! will boot. Embedded MCPRackApp does NOT require
70
- # either flag.
71
- # PARSE_MCP_ENABLED=true
72
-
73
- # X-MCP-API-Key value used by MCPServer and the rake test:mcp_inspector task.
74
- # MCP_API_KEY=changeme-mcp-key
75
-
76
- # Override the inspector port (default 3099) and key when running
77
- # `rake test:mcp_inspector`:
78
- # MCP_INSPECTOR_PORT=3099
79
- # MCP_INSPECTOR_KEY=rake-inspector-key
80
-
81
- # ===========================================================================
82
- # LLM provider for `rake mcp:chat` / `rake mcp:console`
83
- # (also consumed by the LLM-driven integration test files under
84
- # test/lib/parse/agent/mcp_real_llm_*_test.rb)
85
- #
86
- # Pick ONE provider stanza below and uncomment its block. The chat console
87
- # refuses to start without LLM_PROVIDER set.
88
- # ===========================================================================
89
-
90
- # --- Option A: LM Studio (free, local) -------------------------------------
91
- # Start the LM Studio HTTP server first (Server tab → Start Server), with a
92
- # tool-capable model loaded (Qwen2.5-7B-instruct, Llama-3.1-8B-instruct,
93
- # gpt-oss-20b, etc.). The API key value is ignored by LM Studio.
94
- #
95
- # LLM_PROVIDER=lmstudio
96
- # LLM_MODEL=qwen2.5-7b-instruct
97
- # LLM_BASE_URL=http://localhost:1234/v1
98
- # LLM_API_KEY=lm-studio
99
-
100
- # --- Option B: OpenAI gpt-4o-mini (~$0.0001 per run) -----------------------
101
- # Get a key at https://platform.openai.com/api-keys
102
- #
103
- # LLM_PROVIDER=openai
104
- # LLM_API_KEY=sk-proj-...
105
- # LLM_MODEL=gpt-4o-mini
106
- # LLM_BASE_URL=https://api.openai.com/v1 # default; override only if proxying
107
-
108
- # --- Option C: Anthropic Claude Haiku (~$0.001 per run) --------------------
109
- # Get a key at https://console.anthropic.com/settings/keys
110
- #
111
- # LLM_PROVIDER=anthropic
112
- # LLM_API_KEY=sk-ant-api03-...
113
- # LLM_MODEL=claude-haiku-4-5
114
- # LLM_BASE_URL=https://api.anthropic.com/v1
115
-
116
- # --- Legacy LLM endpoint (Parse::Agent#ask path, NOT the MCP smoke test) ---
117
- # Used by the in-process Parse::Agent#ask conversational path, separate from
118
- # the MCP smoke test above. Defaults to a local OpenAI-compatible endpoint.
119
- #
120
- # LLM_ENDPOINT=http://localhost:1234/v1
121
- # OPENAI_API_KEY=
122
- # ANTHROPIC_API_KEY=
123
-
124
- # ===========================================================================
125
- # Embedding providers (Parse::Embeddings)
126
- #
127
- # Used by `Parse::Embeddings.register(...)` in initializers / tests for the
128
- # text-only providers shipped in v5.0: OpenAI, Cohere, Voyage, Jina, Qwen.
129
- # LocalHTTP providers (Ollama, LM Studio, vLLM, self-hosted voyage-4-nano /
130
- # Qwen3-Embedding) read no env var by default — their api_key (if any) is
131
- # passed at registration time.
132
- # ===========================================================================
133
-
134
- # OPENAI_API_KEY=sk-...
135
- # COHERE_API_KEY=
136
- # VOYAGE_API_KEY=pa-...
137
- # JINA_API_KEY=jina_...
138
- # DASHSCOPE_API_KEY=sk-... # Alibaba Cloud DashScope (Qwen 3 embeddings)
data/.env.test DELETED
@@ -1,10 +0,0 @@
1
- # Parse Server Test Configuration
2
- PARSE_TEST_SERVER_URL=http://localhost:29337/parse
3
- PARSE_TEST_APP_ID=psnextItAppId
4
- PARSE_TEST_API_KEY=psnext-it-rest-key
5
- PARSE_TEST_MASTER_KEY=psnextItMasterKey
6
-
7
- # Docker Configuration
8
- PARSE_TEST_USE_DOCKER=true
9
- PARSE_TEST_AUTO_START=false
10
- PARSE_TEST_AUTO_STOP=false