Class: Portage::Ucp::Client::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/portage/ucp/client/session.rb

Overview

Caller-facing object returned by Client.for_adapter/.connect/.discover — same convenience method names as the merchant-side Portage::Ucp::Adapter, regardless of which transport is underneath (loopback/stdio/HTTP; callers never know which they got).

Generates an idempotency_key per mutating call unless the caller supplies one, and runs PaymentTokenGuard client-side before a payment_token goes out over complete_checkout — belt-and-suspenders with the merchant's own guard (§9), not a replacement for it.

A Checkout/Order response with status == "requires_escalation" is returned normally, with its links, not raised as an error — callers must branch on it themselves.

Constant Summary collapse

MUTATING_ACTIONS =
%w[create_cart update_cart cancel_cart create_checkout update_checkout
complete_checkout cancel_checkout create_payment_enrollment].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(transport:, capabilities: nil) ⇒ Session

Returns a new instance of Session.

Parameters:

  • capabilities (Array<String>, nil) (defaults to: nil) —

    reverse-domain capability names advertised by the server, when known upfront (Client.discover populates this from the manifest; Client.for_adapter/.connect leave it nil since nothing was fetched to populate it from).



27
28
29
30
# File 'lib/portage/ucp/client/session.rb', line 27

def initialize(transport:, capabilities: nil)
  @transport = transport
  @capabilities = capabilities
end

Instance Attribute Details

#capabilities ⇒ Object (readonly)

Returns the value of attribute capabilities.



32
33
34
# File 'lib/portage/ucp/client/session.rb', line 32

def capabilities
  @capabilities
end

Instance Method Details

#advertises?(capability_name) ⇒ Boolean?

Returns nil when capabilities weren't known upfront (see #capabilities) — callers with a nil result can't tell either way and should just attempt the call.

Returns:

  • (Boolean, nil) —

    nil when capabilities weren't known upfront (see #capabilities) — callers with a nil result can't tell either way and should just attempt the call.



37
38
39
# File 'lib/portage/ucp/client/session.rb', line 37

def advertises?(capability_name)
  capabilities&.include?(capability_name)
end

#cancel_cart(cart_id:, idempotency_key: nil, meta: nil) ⇒ Object



72
73
74
# File 'lib/portage/ucp/client/session.rb', line 72

def cancel_cart(cart_id:, idempotency_key: nil, meta: nil)
  call("cancel_cart", meta: meta, cart_id: cart_id, idempotency_key: idempotency_key)
end

#cancel_checkout(checkout_id:, idempotency_key: nil, meta: nil) ⇒ Object



117
118
119
# File 'lib/portage/ucp/client/session.rb', line 117

def cancel_checkout(checkout_id:, idempotency_key: nil, meta: nil)
  call("cancel_checkout", meta: meta, checkout_id: checkout_id, idempotency_key: idempotency_key)
end

#complete_checkout(checkout_id:, payment_token:, idempotency_key: nil, handler_id: nil, credential_type: nil, meta: nil) ⇒ Object

handler_id:/credential_type: only matter to Transports::Http (see #complete_checkout_body there) — the loopback/stdio transports splat straight into an Adapter signature with no such keywords, so both are dropped there like context:/cart_id: (their own REMOTE_WIRE_ARGUMENTS). Left nil, Http assumes the one handler it knows how to build a request for (the card handler).



108
109
110
111
112
113
114
115
# File 'lib/portage/ucp/client/session.rb', line 108

def complete_checkout(checkout_id:, payment_token:, idempotency_key: nil, handler_id: nil,
                      credential_type: nil, meta: nil)
  Portage::Ucp::PaymentTokenGuard.validate!(payment_token)
  call("complete_checkout", meta: meta, checkout_id: checkout_id, payment_token: payment_token,
                            idempotency_key: idempotency_key,
                            **(handler_id ? { handler_id: handler_id } : {}),
                            **(credential_type ? { credential_type: credential_type } : {}))
end

#create_cart(line_items:, idempotency_key: nil, context: nil, meta: nil) ⇒ Object



62
63
64
65
# File 'lib/portage/ucp/client/session.rb', line 62

def create_cart(line_items:, idempotency_key: nil, context: nil, meta: nil)
  call("create_cart", meta: meta, line_items: line_items, idempotency_key: idempotency_key,
                      context: context)
end

#create_checkout(line_items:, idempotency_key: nil, fulfillment: nil, cart_id: nil, context: nil, meta: nil) ⇒ Object

fulfillment: (dev.ucp.shopping.fulfillment) is only exercised over the loopback transport today (Portage::Cli::Buy's own-store adapter path) — passed straight through as whatever value the caller built (a Portage::Ucp::CheckoutFulfillment for loopback). Over stdio/HTTP it would need a JSON wire shape this gem doesn't build yet, so callers on those transports should leave it nil. cart_id: converts an existing cart into a checkout rather than re-listing its contents from scratch — HTTP only (see Transports::Http#wrap_line_items); line_items: stays required because the live server rejects a cart_id-only body.



86
87
88
89
90
91
# File 'lib/portage/ucp/client/session.rb', line 86

def create_checkout(line_items:, idempotency_key: nil, fulfillment: nil, cart_id: nil, context: nil,
                    meta: nil)
  call("create_checkout", meta: meta, line_items: line_items, idempotency_key: idempotency_key,
                          context: context, **(cart_id ? { cart_id: cart_id } : {}),
                          **(fulfillment ? { fulfillment: fulfillment } : {}))
end

#create_payment_enrollment(idempotency_key: nil, meta: nil) ⇒ Object

app.portage-ucp.payment_enrollment (Portage extension, §ref docs/plans/agentic-payments.md Phase 1) — not every adapter advertises this, check #advertises? first.



127
128
129
# File 'lib/portage/ucp/client/session.rb', line 127

def create_payment_enrollment(idempotency_key: nil, meta: nil)
  call("create_payment_enrollment", meta: meta, idempotency_key: idempotency_key)
end

#get_cart(cart_id:, meta: nil) ⇒ Object



60
# File 'lib/portage/ucp/client/session.rb', line 60

def get_cart(cart_id:, meta: nil) = call("get_cart", meta: meta, cart_id: cart_id)

#get_checkout(checkout_id:, meta: nil) ⇒ Object



93
# File 'lib/portage/ucp/client/session.rb', line 93

def get_checkout(checkout_id:, meta: nil) = call("get_checkout", meta: meta, checkout_id: checkout_id)

#get_order(order_id:, meta: nil) ⇒ Object



121
# File 'lib/portage/ucp/client/session.rb', line 121

def get_order(order_id:, meta: nil) = call("get_order", meta: meta, order_id: order_id)

#get_payment_enrollment(enrollment_id:, meta: nil) ⇒ Object



131
132
133
# File 'lib/portage/ucp/client/session.rb', line 131

def get_payment_enrollment(enrollment_id:, meta: nil)
  call("get_payment_enrollment", meta: meta, enrollment_id: enrollment_id)
end

#get_product(product_id:, context: nil, meta: nil) ⇒ Object



52
53
54
# File 'lib/portage/ucp/client/session.rb', line 52

def get_product(product_id:, context: nil, meta: nil)
  call("get_product", meta: meta, product_id: product_id, context: context)
end


122
# File 'lib/portage/ucp/client/session.rb', line 122

def link_identity(oauth_token:, meta: nil) = call("link_identity", meta: meta, oauth_token: oauth_token)

#lookup_catalog(product_ids:, context: nil, meta: nil) ⇒ Object



56
57
58
# File 'lib/portage/ucp/client/session.rb', line 56

def lookup_catalog(product_ids:, context: nil, meta: nil)
  call("lookup_catalog", meta: meta, product_ids: product_ids, context: context)
end

#search_catalog(query:, limit: 20, context: nil, meta: nil) ⇒ Object

context: is the UCP context object — buyer locale hints (address_country, address_region, postal_code, currency, language). Optional on paper, effectively required against a real store: see Transports::Http#with_context for what a store does with a cart built without one. Ignored by the loopback/stdio transports, which talk to this gem's own flat-argument server.



47
48
49
50
# File 'lib/portage/ucp/client/session.rb', line 47

def search_catalog(query:, limit: 20, context: nil,
                   meta: nil)
  call("search_catalog", meta: meta, query: query, limit: limit, context: context)
end

#update_cart(cart_id:, line_items:, idempotency_key: nil, context: nil, meta: nil) ⇒ Object



67
68
69
70
# File 'lib/portage/ucp/client/session.rb', line 67

def update_cart(cart_id:, line_items:, idempotency_key: nil, context: nil, meta: nil)
  call("update_cart", meta: meta, cart_id: cart_id, line_items: line_items,
                      idempotency_key: idempotency_key, context: context)
end

#update_checkout(checkout_id:, line_items:, idempotency_key: nil, fulfillment: nil, context: nil, meta: nil) ⇒ Object



95
96
97
98
99
100
# File 'lib/portage/ucp/client/session.rb', line 95

def update_checkout(checkout_id:, line_items:, idempotency_key: nil, fulfillment: nil, context: nil,
                    meta: nil)
  call("update_checkout", meta: meta, checkout_id: checkout_id, line_items: line_items,
                          idempotency_key: idempotency_key, context: context,
                          **(fulfillment ? { fulfillment: fulfillment } : {}))
end