Class: ZeroClick::Sellers::Middleware::Meter

Inherits:
Base
  • Object
show all
Defined in:
lib/zeroclick/sellers/middleware.rb

Overview

Guards a billable endpoint: verifies the signature, confirms the buyer can pay, and — if the app responds 2xx — reports the usage.

use ZeroClick::Sellers::Middleware::Meter,
  seller: SELLER, service_slug: "extractor",
  usage: [ZeroClick::Sellers::UsageItem.new(meter_slug: "requests", quantity: 1)]

Inside the app, the request body still reads normally: verification consumes rack.input and this replaces it with a fresh stream over the same bytes.

Every usage item must carry an explicit quantity, and it refuses the others at wire-up. Meter settles usage automatically from what it declared, so an item with only a max_quantity ceiling — or with neither quantity nor max_quantity — has no settled amount, and inventing one would silently mis-bill a delivered 200. That is the exact failure this SDK exists to prevent, so it fails when you build the middleware rather than in production: declare a fixed quantity here and report the variable part with Client#report_usage.

Instance Method Summary collapse

Methods inherited from Base

#call

Constructor Details

#initialize(app, service_slug:, usage:, seller: nil, plan_slug: nil, max_body_bytes: DEFAULT_MAX_BODY_BYTES) ⇒ Meter

Returns a new instance of Meter.

Raises:



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/zeroclick/sellers/middleware.rb', line 186

def initialize(app, service_slug:, usage:, seller: nil, plan_slug: nil,
               max_body_bytes: DEFAULT_MAX_BODY_BYTES)
  super(app, seller: seller, service_slug: service_slug, max_body_bytes: max_body_bytes)
  @usage = Sellers.normalize_usage(usage, operation: "Middleware::Meter", allow_empty: false)
  @plan_slug = plan_slug

  # Meter settles usage from what it declared, so every item must carry
  # a definite quantity. An item that does not — a max_quantity ceiling,
  # or one that defers to the meter's configured per-request default —
  # has no settled amount here, and inventing one would silently
  # mis-bill a delivered 200. That is the exact failure this SDK exists
  # to prevent, so it fails at wire-up rather than in production.
  indefinite = @usage.find { |item| item.quantity.nil? }
  return unless indefinite

  raise Error.new("malformed_input", operation: "Middleware::Meter",
                                     meter_slug: indefinite.meter_slug,
                                     message: "Middleware::Meter needs an explicit quantity on every usage item, and " \
                                              "#{indefinite.meter_slug} has none. It settles usage from what it " \
                                              "declares, so an item carrying a max_quantity ceiling — or neither " \
                                              "quantity nor max_quantity — has no settled amount to report. Declare a " \
                                              "fixed quantity here and report the variable part with Client#report_usage.")
end