mpp-rb 0.1.5 → 0.1.7

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +150 -0
  3. data/lib/mpp/challenge.rb +31 -8
  4. data/lib/mpp/challenge_echo.rb +14 -3
  5. data/lib/mpp/challenge_id.rb +30 -6
  6. data/lib/mpp/client/transport.rb +1 -1
  7. data/lib/mpp/extensions/mcp/verify.rb +1 -1
  8. data/lib/mpp/methods/evm/charge_intent.rb +38 -17
  9. data/lib/mpp/methods/evm/evm_method.rb +18 -2
  10. data/lib/mpp/methods/evm.rb +5 -2
  11. data/lib/mpp/methods/stripe/analytics_metadata.rb +24 -0
  12. data/lib/mpp/methods/stripe/charge_intent.rb +34 -11
  13. data/lib/mpp/methods/stripe/crypto_payment_recorder.rb +92 -0
  14. data/lib/mpp/methods/stripe/defaults.rb +1 -0
  15. data/lib/mpp/methods/stripe/machine_payments.rb +128 -0
  16. data/lib/mpp/methods/stripe/payment_intent_method.rb +103 -0
  17. data/lib/mpp/methods/stripe/payment_intent_options.rb +81 -0
  18. data/lib/mpp/methods/stripe/stripe_method.rb +30 -3
  19. data/lib/mpp/methods/stripe.rb +26 -0
  20. data/lib/mpp/methods/tempo/client_method.rb +58 -12
  21. data/lib/mpp/methods/tempo/defaults.rb +51 -0
  22. data/lib/mpp/methods/tempo/intents.rb +195 -125
  23. data/lib/mpp/methods/tempo/relay.rb +33 -31
  24. data/lib/mpp/methods/tempo/schemas.rb +3 -4
  25. data/lib/mpp/parsing.rb +29 -4
  26. data/lib/mpp/server/compose.rb +32 -15
  27. data/lib/mpp/server/decorator.rb +3 -1
  28. data/lib/mpp/server/intent.rb +6 -1
  29. data/lib/mpp/server/intent_lifecycle.rb +41 -0
  30. data/lib/mpp/server/method.rb +41 -0
  31. data/lib/mpp/server/middleware.rb +16 -2
  32. data/lib/mpp/server/mpp_handler.rb +87 -21
  33. data/lib/mpp/server/verify.rb +25 -15
  34. data/lib/mpp/server.rb +1 -0
  35. data/lib/mpp/validation.rb +27 -0
  36. data/lib/mpp/version.rb +1 -1
  37. data/lib/mpp.rb +14 -3
  38. metadata +22 -1
@@ -10,7 +10,7 @@ module Mpp
10
10
  class MppHandler
11
11
  extend T::Sig
12
12
 
13
- REQUEST_OPTION_KEYS = [:body, :url, :payment_signature, :accept_payment, :http_method].freeze
13
+ REQUEST_OPTION_KEYS = [:body, :url, :payment_signature, :accept_payment, :http_method, :payment_authorization].freeze
14
14
 
15
15
  sig { returns(T.untyped) }
16
16
  attr_reader :method
@@ -27,6 +27,12 @@ module Mpp
27
27
  sig { returns(T::Hash[String, T.untyped]) }
28
28
  attr_reader :defaults
29
29
 
30
+ sig { returns(T::Boolean) }
31
+ attr_reader :requires_auth
32
+
33
+ sig { returns(T.nilable(String)) }
34
+ attr_reader :credential_header
35
+
30
36
  sig do
31
37
  params(
32
38
  realm: String,
@@ -34,16 +40,21 @@ module Mpp
34
40
  method: T.untyped,
35
41
  methods: T.nilable(T::Array[T.untyped]),
36
42
  defaults: T.nilable(T::Hash[String, T.untyped]),
37
- events: T.nilable(Mpp::Events::Dispatcher)
43
+ events: T.nilable(Mpp::Events::Dispatcher),
44
+ requires_auth: T::Boolean
38
45
  ).void
39
46
  end
40
- def initialize(realm:, secret_key:, method: nil, methods: nil, defaults: nil, events: nil)
47
+ def initialize(realm:, secret_key:, method: nil, methods: nil, defaults: nil, events: nil, requires_auth: false)
41
48
  @methods = T.let(normalize_methods(method, methods), T::Array[T.untyped])
42
49
  @method = T.let(@methods.first, T.untyped)
43
50
  @realm = T.let(realm, String)
44
51
  @secret_key = T.let(secret_key, String)
45
52
  @defaults = T.let(defaults || {}, T::Hash[String, T.untyped])
46
53
  @events = T.let(events || Mpp::Events.server_dispatcher, Mpp::Events::Dispatcher)
54
+ @method_hook_events = T.let(Mpp::Events.server_dispatcher, Mpp::Events::Dispatcher)
55
+ @requires_auth = T.let(requires_auth, T::Boolean)
56
+ @credential_header = T.let(requires_auth ? Mpp::PAYMENT_AUTHORIZATION_HEADER : nil, T.nilable(String))
57
+ register_method_payment_success
47
58
  end
48
59
 
49
60
  # Create with auto-detected realm and secret_key.
@@ -53,16 +64,18 @@ module Mpp
53
64
  methods: T.nilable(T::Array[T.untyped]),
54
65
  realm: T.untyped,
55
66
  secret_key: T.untyped,
56
- events: T.nilable(Mpp::Events::Dispatcher)
67
+ events: T.nilable(Mpp::Events::Dispatcher),
68
+ requires_auth: T::Boolean
57
69
  ).returns(T.attached_class)
58
70
  end
59
- def self.create(method: nil, methods: nil, realm: nil, secret_key: nil, events: nil)
71
+ def self.create(method: nil, methods: nil, realm: nil, secret_key: nil, events: nil, requires_auth: false)
60
72
  new(
61
73
  method: method,
62
74
  methods: methods,
63
75
  realm: realm || Defaults.detect_realm,
64
76
  secret_key: secret_key || Defaults.detect_secret_key,
65
- events: events
77
+ events: events,
78
+ requires_auth: requires_auth
66
79
  )
67
80
  end
68
81
 
@@ -86,6 +99,14 @@ module Mpp
86
99
  on(Mpp::Events::PAYMENT_SUCCESS, handler, &block)
87
100
  end
88
101
 
102
+ # Select the HTTP header value that carries the Payment credential.
103
+ # When requires_auth is true, Payment credentials ride in
104
+ # Payment-Authorization so Authorization can hold application auth.
105
+ sig { params(authorization: T.nilable(String), payment_authorization: T.nilable(String)).returns(T.nilable(String)) }
106
+ def payment_credential_value(authorization, payment_authorization = nil)
107
+ @requires_auth ? payment_authorization : authorization
108
+ end
109
+
89
110
  # Combine method offers into a single callable that presents every method.
90
111
  sig { params(entries: T.untyped).returns(ComposedHandler) }
91
112
  def compose(*entries)
@@ -109,9 +130,10 @@ module Mpp
109
130
 
110
131
  # Handle a charge intent.
111
132
  #
112
- # With a single registered charge method this returns Challenge or
113
- # [Credential, Receipt]. With multiple charge methods it implicitly
114
- # composes them and returns a ComposedResult.
133
+ # With a single registered charge method offering a single currency this
134
+ # returns Challenge or [Credential, Receipt]. With multiple charge methods,
135
+ # or a method accepting several currencies, it implicitly composes one
136
+ # offer per method and currency and returns a ComposedResult.
115
137
  sig { params(authorization: T.nilable(String), amount: String, kwargs: T.untyped).returns(T.untyped) }
116
138
  def charge(authorization, amount, **kwargs)
117
139
  charge_methods = @methods.select { |candidate| candidate.intents.key?("charge") }
@@ -119,11 +141,12 @@ module Mpp
119
141
 
120
142
  request_opts = kwargs.slice(*REQUEST_OPTION_KEYS)
121
143
  offer_opts = kwargs.except(*REQUEST_OPTION_KEYS)
144
+ payment = payment_credential_value(authorization, request_opts[:payment_authorization])
122
145
 
123
- if charge_methods.length == 1
146
+ if charge_methods.length == 1 && MethodHelper.offer_currencies(charge_methods.first, offer_opts).nil?
124
147
  return charge_one(
125
148
  charge_methods.first,
126
- authorization,
149
+ payment,
127
150
  amount,
128
151
  **request_opts,
129
152
  **offer_opts
@@ -133,6 +156,7 @@ module Mpp
133
156
  entries = charge_methods.map { |candidate| [candidate, offer_opts.merge(amount: amount)] }
134
157
  ComposedHandler.from_entries(self, entries).call(
135
158
  authorization: authorization,
159
+ payment_authorization: request_opts[:payment_authorization],
136
160
  payment_signature: request_opts[:payment_signature],
137
161
  body: request_opts[:body],
138
162
  url: request_opts[:url],
@@ -142,8 +166,10 @@ module Mpp
142
166
  end
143
167
 
144
168
  # Verify or challenge a single method. Used by compose and charge.
145
- sig { params(method: T.untyped, authorization: T.nilable(String), amount: String, kwargs: T.untyped).returns(T.untyped) }
146
- def charge_one(method, authorization, amount, **kwargs)
169
+ # The optional request guard can omit an offer after its canonical request
170
+ # is built, ensuring the guard and challenge use the exact same request.
171
+ sig { params(method: T.untyped, authorization: T.nilable(String), amount: String, kwargs: T.untyped, request_guard: T.nilable(T.proc.params(request: T::Hash[String, T.untyped]).returns(T::Boolean))).returns(T.untyped) }
172
+ def charge_one(method, authorization, amount, **kwargs, &request_guard)
147
173
  intent = method.intents["charge"]
148
174
  raise ArgumentError, "Method #{method.name} does not support charge intent" unless intent
149
175
 
@@ -151,7 +177,9 @@ module Mpp
151
177
  url = kwargs[:url]
152
178
  payment_signature = kwargs[:payment_signature]
153
179
  offer_opts = kwargs.except(*REQUEST_OPTION_KEYS)
180
+ intent, offer_opts = Mpp::Server::MethodHelper.prepare_intent(method, intent, offer_opts)
154
181
  request = build_charge_request(method, amount, **offer_opts)
182
+ return nil if request_guard && !request_guard.call(request)
155
183
 
156
184
  if payment_signature && method.respond_to?(:bind_x402_credential)
157
185
  return verify_x402(
@@ -177,7 +205,9 @@ module Mpp
177
205
  description: offer_opts[:description],
178
206
  expires: offer_opts[:expires],
179
207
  events: @events,
180
- body: body
208
+ method_hook_events: @method_hook_events,
209
+ body: body,
210
+ header: @credential_header
181
211
  )
182
212
  end
183
213
 
@@ -187,7 +217,6 @@ module Mpp
187
217
  currency = kwargs[:currency]
188
218
  recipient = kwargs[:recipient]
189
219
  external_id = kwargs[:external_id]
190
- memo = kwargs[:memo]
191
220
  fee_payer = if kwargs.key?(:fee_payer)
192
221
  kwargs[:fee_payer]
193
222
  else
@@ -197,7 +226,7 @@ module Mpp
197
226
  extra = kwargs[:extra]
198
227
  mppx_scope = kwargs[:mppx_scope]
199
228
 
200
- resolved_currency = currency || (method.respond_to?(:currency) ? method.currency : nil)
229
+ resolved_currency = currency || primary_currency(method)
201
230
  resolved_recipient = recipient || (method.respond_to?(:recipient) ? method.recipient : nil)
202
231
  raise ArgumentError, "currency must be set on the method or passed to charge()" unless resolved_currency
203
232
  raise ArgumentError, "recipient must be set on the method or passed to charge()" unless resolved_recipient
@@ -228,10 +257,9 @@ module Mpp
228
257
  resolved_chain_id = chain_id
229
258
  resolved_chain_id ||= method.chain_id if method.respond_to?(:chain_id)
230
259
 
231
- if memo || fee_payer || !resolved_chain_id.nil?
260
+ if fee_payer || !resolved_chain_id.nil?
232
261
  method_details = {}
233
262
  method_details["chainId"] = resolved_chain_id unless resolved_chain_id.nil?
234
- method_details["memo"] = memo if memo
235
263
  method_details["feePayer"] = true if fee_payer
236
264
  request["methodDetails"] = method_details
237
265
  end
@@ -268,6 +296,15 @@ module Mpp
268
296
  list
269
297
  end
270
298
 
299
+ # A method's first accepted currency, else its singular currency.
300
+ sig { params(method: T.untyped).returns(T.untyped) }
301
+ def primary_currency(method)
302
+ currencies = method.respond_to?(:currencies) ? method.currencies : nil
303
+ return currencies.first if currencies.is_a?(Array) && !currencies.empty?
304
+
305
+ method.respond_to?(:currency) ? method.currency : nil
306
+ end
307
+
271
308
  sig { params(key: String).returns(T.untyped) }
272
309
  def resolve_method_key(key)
273
310
  name, intent = key.split("/", 2)
@@ -304,7 +341,8 @@ module Mpp
304
341
  description,
305
342
  nil,
306
343
  expires,
307
- body
344
+ body,
345
+ @credential_header
308
346
  )
309
347
  method_context = {name: method.name, intent: intent.name}
310
348
 
@@ -317,7 +355,7 @@ module Mpp
317
355
  body: body,
318
356
  http_method: http_method
319
357
  )
320
- receipt = intent.verify(credential, challenge.request)
358
+ receipt = IntentLifecycle.call(intent, credential, challenge.request)
321
359
  rescue => error
322
360
  if @events.has_handlers?(Mpp::Events::PAYMENT_FAILED)
323
361
  Verify.emit_payment_failed(
@@ -330,6 +368,9 @@ module Mpp
330
368
  retry_challenge: challenge
331
369
  )
332
370
  end
371
+ if error.is_a?(Mpp::PaymentError) && error.status != 402
372
+ raise
373
+ end
333
374
  if error.is_a?(Mpp::ParseError) || error.is_a?(Mpp::VerificationError) || error.is_a?(Mpp::PaymentError)
334
375
  if @events.has_handlers?(Mpp::Events::CHALLENGE_CREATED)
335
376
  Verify.emit_challenge_created(
@@ -346,9 +387,10 @@ module Mpp
346
387
  raise
347
388
  end
348
389
 
349
- if @events.has_handlers?(Mpp::Events::PAYMENT_SUCCESS)
390
+ if @events.has_handlers?(Mpp::Events::PAYMENT_SUCCESS) || @method_hook_events.has_handlers?(Mpp::Events::PAYMENT_SUCCESS)
350
391
  Verify.emit_payment_success(
351
392
  dispatcher: @events,
393
+ method_hook_dispatcher: @method_hook_events,
352
394
  challenge: challenge,
353
395
  credential: credential,
354
396
  method: method_context,
@@ -358,6 +400,30 @@ module Mpp
358
400
  end
359
401
  [credential, receipt]
360
402
  end
403
+
404
+ private
405
+
406
+ sig { void }
407
+ def register_method_payment_success
408
+ @methods.each do |payment_method|
409
+ next unless payment_method.respond_to?(:on_payment_success)
410
+
411
+ hook = payment_method.on_payment_success
412
+ next if hook.nil?
413
+ raise ArgumentError, "on_payment_success must be callable" unless hook.respond_to?(:call)
414
+
415
+ method_name = payment_method.name
416
+ intent_names = payment_method.intents.each_value.map { |intent| intent.name }
417
+ @method_hook_events.on(Mpp::Events::PAYMENT_SUCCESS) do |payload|
418
+ event_method = payload[:method]
419
+ next unless event_method.is_a?(Hash)
420
+ next unless event_method[:name] == method_name
421
+ next unless intent_names.include?(event_method[:intent])
422
+
423
+ hook.call(payload)
424
+ end
425
+ end
426
+ end
361
427
  end
362
428
  end
363
429
  end
@@ -15,17 +15,17 @@ module Mpp
15
15
  # Verify a payment credential or generate a new challenge.
16
16
  #
17
17
  # Returns Challenge (payment required) or [Credential, Receipt] (verified).
18
- sig { params(authorization: T.nilable(String), intent: T.untyped, request: T::Hash[String, T.untyped], realm: String, secret_key: String, method: T.nilable(String), description: T.nilable(String), meta: T.nilable(T::Hash[String, T.untyped]), expires: T.nilable(String), events: T.nilable(Mpp::Events::Dispatcher), body: T.untyped).returns(T.untyped) }
18
+ sig { params(authorization: T.nilable(String), intent: T.untyped, request: T::Hash[String, T.untyped], realm: String, secret_key: String, method: T.nilable(String), description: T.nilable(String), meta: T.nilable(T::Hash[String, T.untyped]), expires: T.nilable(String), events: T.nilable(Mpp::Events::Dispatcher), method_hook_events: T.nilable(Mpp::Events::Dispatcher), body: T.untyped, header: T.nilable(String)).returns(T.untyped) }
19
19
  def verify_or_challenge(authorization:, intent:, request:, realm:, secret_key:,
20
- method: nil, description: nil, meta: nil, expires: nil, events: nil, body: nil)
20
+ method: nil, description: nil, meta: nil, expires: nil, events: nil, method_hook_events: nil, body: nil, header: nil)
21
21
  method_name = method || "tempo"
22
22
  request = Mpp::Units.transform_units(request)
23
23
  dispatcher = events
24
- events_enabled = dispatcher&.has_handlers?
24
+ events_enabled = dispatcher&.has_handlers? || method_hook_events&.has_handlers?
25
25
  method_context = events_enabled ? {name: method_name, intent: intent.name} : nil
26
26
 
27
27
  new_challenge = Kernel.lambda { |credential = nil, error = nil, submitted_challenge = nil|
28
- challenge = create_challenge(method_name, intent.name, request, realm, secret_key, description, meta, expires, body)
28
+ challenge = create_challenge(method_name, intent.name, request, realm, secret_key, description, meta, expires, body, header)
29
29
  if error && dispatcher&.has_handlers?(Mpp::Events::PAYMENT_FAILED)
30
30
  emit_payment_failed(
31
31
  dispatcher: dispatcher,
@@ -79,7 +79,8 @@ module Mpp
79
79
  request: echo_request,
80
80
  expires: echo.expires,
81
81
  digest: echo.digest,
82
- opaque: echo_opaque
82
+ opaque: echo_opaque,
83
+ header: echo.header
83
84
  )
84
85
  unless Mpp.secure_compare(echo.id, expected_id)
85
86
  return new_challenge.call(
@@ -157,7 +158,7 @@ module Mpp
157
158
  end
158
159
 
159
160
  begin
160
- receipt = intent.verify(credential, request)
161
+ receipt = IntentLifecycle.call(intent, credential, request)
161
162
  rescue => e
162
163
  if dispatcher&.has_handlers?(Mpp::Events::PAYMENT_FAILED)
163
164
  emit_payment_failed(
@@ -172,9 +173,10 @@ module Mpp
172
173
  end
173
174
  Kernel.raise
174
175
  end
175
- if dispatcher&.has_handlers?(Mpp::Events::PAYMENT_SUCCESS)
176
+ if dispatcher&.has_handlers?(Mpp::Events::PAYMENT_SUCCESS) || method_hook_events&.has_handlers?(Mpp::Events::PAYMENT_SUCCESS)
176
177
  emit_payment_success(
177
178
  dispatcher: dispatcher,
179
+ method_hook_dispatcher: method_hook_events,
178
180
  challenge: echo,
179
181
  credential: credential,
180
182
  method: T.must(method_context),
@@ -185,9 +187,9 @@ module Mpp
185
187
  [credential, receipt]
186
188
  end
187
189
 
188
- sig { params(method: String, intent_name: String, request: T::Hash[String, T.untyped], realm: String, secret_key: String, description: T.nilable(String), meta: T.nilable(T::Hash[String, T.untyped]), expires: T.nilable(String), body: T.untyped).returns(Mpp::Challenge) }
190
+ sig { params(method: String, intent_name: String, request: T::Hash[String, T.untyped], realm: String, secret_key: String, description: T.nilable(String), meta: T.nilable(T::Hash[String, T.untyped]), expires: T.nilable(String), body: T.untyped, header: T.nilable(String)).returns(Mpp::Challenge) }
189
191
  def create_challenge(method, intent_name, request, realm, secret_key,
190
- description = nil, meta = nil, expires = nil, body = nil)
192
+ description = nil, meta = nil, expires = nil, body = nil, header = nil)
191
193
  expires = nil if expires && !expires.is_a?(String)
192
194
 
193
195
  if expires.nil?
@@ -205,7 +207,8 @@ module Mpp
205
207
  expires: expires,
206
208
  digest: digest,
207
209
  description: description,
208
- meta: meta
210
+ meta: meta,
211
+ header: header
209
212
  )
210
213
  end
211
214
 
@@ -258,17 +261,24 @@ module Mpp
258
261
  dispatcher.emit(Mpp::Events::PAYMENT_FAILED, payload)
259
262
  end
260
263
 
261
- sig { params(dispatcher: Mpp::Events::Dispatcher, challenge: T.untyped, credential: T.untyped, method: T::Hash[Symbol, T.untyped], receipt: T.untyped, request: T::Hash[String, T.untyped]).void }
262
- def emit_payment_success(dispatcher:, challenge:, credential:, method:, receipt:, request:)
263
- return unless dispatcher.has_handlers?(Mpp::Events::PAYMENT_SUCCESS)
264
+ # Method hooks are owned by a handler, while `dispatcher` may be shared
265
+ # by many handlers. Emit the same payload to each without exposing that
266
+ # handler ownership in the public event payload.
267
+ sig { params(dispatcher: T.nilable(Mpp::Events::Dispatcher), challenge: T.untyped, credential: T.untyped, method: T::Hash[Symbol, T.untyped], receipt: T.untyped, request: T::Hash[String, T.untyped], method_hook_dispatcher: T.nilable(Mpp::Events::Dispatcher)).void }
268
+ def emit_payment_success(dispatcher:, challenge:, credential:, method:, receipt:, request:, method_hook_dispatcher: nil)
269
+ public_handlers = dispatcher&.has_handlers?(Mpp::Events::PAYMENT_SUCCESS)
270
+ hook_handlers = method_hook_dispatcher&.has_handlers?(Mpp::Events::PAYMENT_SUCCESS)
271
+ return unless public_handlers || hook_handlers
264
272
 
265
- dispatcher.emit(Mpp::Events::PAYMENT_SUCCESS, {
273
+ payload = {
266
274
  challenge: challenge,
267
275
  credential: credential,
268
276
  method: method,
269
277
  receipt: receipt,
270
278
  request: request
271
- })
279
+ }
280
+ dispatcher.emit(Mpp::Events::PAYMENT_SUCCESS, payload) if public_handlers
281
+ method_hook_dispatcher.emit(Mpp::Events::PAYMENT_SUCCESS, payload) if hook_handlers && method_hook_dispatcher != dispatcher
272
282
  end
273
283
  end
274
284
  end
data/lib/mpp/server.rb CHANGED
@@ -6,6 +6,7 @@ module Mpp
6
6
  autoload :Defaults, "mpp/server/defaults"
7
7
  autoload :Intent, "mpp/server/intent"
8
8
  autoload :FunctionalIntent, "mpp/server/intent"
9
+ autoload :IntentLifecycle, "mpp/server/intent_lifecycle"
9
10
  autoload :Method, "mpp/server/method"
10
11
  autoload :Verify, "mpp/server/verify"
11
12
  autoload :MppHandler, "mpp/server/mpp_handler"
@@ -0,0 +1,27 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Mpp
5
+ # Non-mutating validation result, matching mppx's Method.Validation fields.
6
+ # Details are method-specific, not a receipt or a guarantee of settlement.
7
+ # Challenge issuance and route binding are checked by the server, not by
8
+ # constructing this record or calling a rail's validate method directly.
9
+ Validation = Data.define(:challenge, :credential, :intent, :method, :request, :details, :source) do
10
+ extend T::Sig
11
+
12
+ sig do
13
+ params(
14
+ challenge: Mpp::ChallengeEcho,
15
+ credential: Mpp::Credential,
16
+ intent: String,
17
+ method: String,
18
+ request: T::Hash[String, T.untyped],
19
+ details: T.untyped,
20
+ source: T.nilable(String)
21
+ ).void
22
+ end
23
+ def initialize(challenge:, credential:, intent:, method:, request:, details:, source: nil)
24
+ super
25
+ end
26
+ end
27
+ end
data/lib/mpp/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Mpp
5
- VERSION = "0.1.5"
5
+ VERSION = "0.1.7"
6
6
  end
data/lib/mpp.rb CHANGED
@@ -11,10 +11,14 @@ require_relative "mpp/secure_compare"
11
11
  module Mpp
12
12
  extend T::Sig
13
13
 
14
+ AUTHORIZATION_HEADER = T.let("Authorization", String)
15
+ PAYMENT_AUTHORIZATION_HEADER = T.let("Payment-Authorization", String)
16
+
14
17
  autoload :Challenge, "mpp/challenge"
15
18
  autoload :ChallengeEcho, "mpp/challenge_echo"
16
19
  autoload :Credential, "mpp/credential"
17
20
  autoload :Receipt, "mpp/receipt"
21
+ autoload :Validation, "mpp/validation"
18
22
  autoload :Parsing, "mpp/parsing"
19
23
  autoload :Json, "mpp/json"
20
24
  autoload :BodyDigest, "mpp/body_digest"
@@ -43,9 +47,16 @@ module Mpp
43
47
  autoload :MCP, "mpp/extensions/mcp"
44
48
  end
45
49
 
46
- sig { params(method: T.untyped, methods: T.nilable(T::Array[T.untyped]), realm: T.untyped, secret_key: T.untyped, events: T.nilable(Mpp::Events::Dispatcher)).returns(T.untyped) }
47
- def self.create(method: nil, methods: nil, realm: nil, secret_key: nil, events: nil)
48
- Server::MppHandler.create(method: method, methods: methods, realm: realm, secret_key: secret_key, events: events)
50
+ sig { params(method: T.untyped, methods: T.nilable(T::Array[T.untyped]), realm: T.untyped, secret_key: T.untyped, events: T.nilable(Mpp::Events::Dispatcher), requires_auth: T::Boolean).returns(T.untyped) }
51
+ def self.create(method: nil, methods: nil, realm: nil, secret_key: nil, events: nil, requires_auth: false)
52
+ Server::MppHandler.create(
53
+ method: method,
54
+ methods: methods,
55
+ realm: realm,
56
+ secret_key: secret_key,
57
+ events: events,
58
+ requires_auth: requires_auth
59
+ )
49
60
  end
50
61
 
51
62
  # Error hierarchy
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mpp-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stripe
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.3'
40
+ - !ruby/object:Gem::Dependency
41
+ name: sorbet-runtime
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
40
54
  description: Ruby SDK for the Machine Payments Protocol (MPP) — an HTTP 402 Payment
41
55
  Authentication scheme.
42
56
  executables: []
@@ -73,9 +87,14 @@ files:
73
87
  - lib/mpp/methods/evm/charge_intent.rb
74
88
  - lib/mpp/methods/evm/evm_method.rb
75
89
  - lib/mpp/methods/stripe.rb
90
+ - lib/mpp/methods/stripe/analytics_metadata.rb
76
91
  - lib/mpp/methods/stripe/charge_intent.rb
77
92
  - lib/mpp/methods/stripe/client_method.rb
93
+ - lib/mpp/methods/stripe/crypto_payment_recorder.rb
78
94
  - lib/mpp/methods/stripe/defaults.rb
95
+ - lib/mpp/methods/stripe/machine_payments.rb
96
+ - lib/mpp/methods/stripe/payment_intent_method.rb
97
+ - lib/mpp/methods/stripe/payment_intent_options.rb
79
98
  - lib/mpp/methods/stripe/stripe_method.rb
80
99
  - lib/mpp/methods/tempo.rb
81
100
  - lib/mpp/methods/tempo/account.rb
@@ -101,6 +120,7 @@ files:
101
120
  - lib/mpp/server/decorator.rb
102
121
  - lib/mpp/server/defaults.rb
103
122
  - lib/mpp/server/intent.rb
123
+ - lib/mpp/server/intent_lifecycle.rb
104
124
  - lib/mpp/server/method.rb
105
125
  - lib/mpp/server/middleware.rb
106
126
  - lib/mpp/server/mpp_handler.rb
@@ -108,6 +128,7 @@ files:
108
128
  - lib/mpp/server/verify.rb
109
129
  - lib/mpp/store.rb
110
130
  - lib/mpp/units.rb
131
+ - lib/mpp/validation.rb
111
132
  - lib/mpp/version.rb
112
133
  - lib/mpp/x402.rb
113
134
  - lib/mpp/x402/facilitator.rb