portage-ucp 0.13.0 → 0.14.0
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 +10 -0
- data/lib/generators/portage/ucp/install/templates/portage_ucp.rb +2 -2
- data/lib/portage/ucp/capabilities/cart.rb +1 -0
- data/lib/portage/ucp/capabilities/catalog.rb +1 -0
- data/lib/portage/ucp/capabilities/checkout.rb +1 -0
- data/lib/portage/ucp/capabilities/discount.rb +1 -0
- data/lib/portage/ucp/capabilities/fulfillment.rb +1 -0
- data/lib/portage/ucp/capabilities/order.rb +1 -0
- data/lib/portage/ucp/capability.rb +7 -2
- data/lib/portage/ucp/configuration.rb +1 -1
- data/lib/portage/ucp/manifest.rb +31 -9
- data/lib/portage/ucp/schema_validator.rb +3 -3
- data/lib/portage/ucp/value_objects.rb +3 -1
- data/lib/portage/ucp/version.rb +1 -1
- data/lib/portage/ucp/wire_envelope.rb +1 -1
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/capability.json +11 -8
- data/schemas/2026-08-25/schemas/common/identity_linking.json +133 -0
- data/schemas/2026-08-25/schemas/common/location_lookup.json +108 -0
- data/schemas/2026-08-25/schemas/common/location_search.json +72 -0
- data/schemas/2026-08-25/schemas/common/loyalty.json +294 -0
- data/schemas/2026-08-25/schemas/common/payment_ap2_mandate.json +91 -0
- data/schemas/2026-08-25/schemas/common/payment_authentication.json +90 -0
- data/schemas/2026-08-25/schemas/common/payment_split_payments.json +82 -0
- data/schemas/2026-08-25/schemas/common/payment_terms.json +92 -0
- data/schemas/2026-08-25/schemas/common/types/actions.json +42 -0
- data/schemas/2026-08-25/schemas/common/types/amenity_type.json +13 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/amount.json +4 -3
- data/schemas/2026-08-25/schemas/common/types/available_payment_instrument.json +20 -0
- data/schemas/2026-08-25/schemas/common/types/binding.json +22 -0
- data/schemas/2026-08-25/schemas/common/types/business_split_payments_config.json +25 -0
- data/schemas/2026-08-25/schemas/common/types/card_credential.json +78 -0
- data/schemas/2026-08-25/schemas/common/types/card_payment_instrument.json +77 -0
- data/schemas/2026-08-25/schemas/common/types/constraint_expression.json +71 -0
- data/schemas/2026-08-25/schemas/common/types/context.json +66 -0
- data/schemas/2026-08-25/schemas/common/types/daily_hour.json +36 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/description.json +2 -2
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/error_code.json +3 -3
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/error_response.json +4 -4
- data/schemas/2026-08-25/schemas/common/types/exception_hour.json +38 -0
- data/schemas/2026-08-25/schemas/common/types/geo.json +25 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/info_code.json +3 -3
- data/schemas/2026-08-25/schemas/common/types/instrument_group.json +32 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/link.json +3 -3
- data/schemas/2026-08-25/schemas/common/types/locality.json +22 -0
- data/schemas/2026-08-25/schemas/common/types/location.json +93 -0
- data/schemas/2026-08-25/schemas/common/types/location_distance.json +23 -0
- data/schemas/2026-08-25/schemas/common/types/location_filter.json +43 -0
- data/schemas/2026-08-25/schemas/common/types/location_serves.json +80 -0
- data/schemas/2026-08-25/schemas/common/types/location_summary.json +29 -0
- data/schemas/2026-08-25/schemas/common/types/measure.json +25 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/media.json +3 -3
- data/schemas/2026-08-25/schemas/common/types/message.json +18 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/message_error.json +5 -5
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/message_info.json +4 -4
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/message_warning.json +4 -4
- data/schemas/2026-08-25/schemas/common/types/network_token_credential.json +68 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/pagination.json +3 -4
- data/schemas/2026-08-25/schemas/common/types/pan_credential.json +54 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common/types}/payment.json +3 -3
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/payment_credential.json +2 -2
- data/schemas/2026-08-25/schemas/common/types/payment_identity.json +16 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/payment_instrument.json +5 -5
- data/schemas/2026-08-25/schemas/common/types/payment_schedule.json +37 -0
- data/schemas/2026-08-25/schemas/common/types/payment_term.json +35 -0
- data/schemas/2026-08-25/schemas/common/types/policy.json +34 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/postal_address.json +2 -2
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/price.json +3 -3
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/price_filter.json +4 -4
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/price_range.json +5 -5
- data/schemas/2026-08-25/schemas/common/types/quantity_unit.json +22 -0
- data/schemas/2026-08-25/schemas/common/types/request_constraints.json +47 -0
- data/schemas/2026-08-25/schemas/common/types/reverse_domain_name.json +17 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/signals.json +3 -3
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/signed_amount.json +5 -3
- data/schemas/2026-08-25/schemas/common/types/time_interval.json +29 -0
- data/schemas/2026-08-25/schemas/common/types/token_credential.json +29 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/total.json +3 -3
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/totals.json +4 -4
- data/schemas/2026-08-25/schemas/common/types/unit.json +49 -0
- data/schemas/{2026-04-08/schemas/shopping → 2026-08-25/schemas/common}/types/warning_code.json +4 -3
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/payment_handler.json +4 -4
- data/schemas/2026-08-25/schemas/profile.json +266 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/service.json +6 -6
- data/schemas/2026-08-25/schemas/shopping/buyer_consent.json +167 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/cart.json +32 -37
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/catalog_lookup.json +46 -22
- data/schemas/2026-08-25/schemas/shopping/catalog_search.json +76 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/checkout.json +29 -16
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/discount.json +9 -9
- data/schemas/2026-08-25/schemas/shopping/fulfillment.json +440 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/order.json +19 -11
- data/schemas/2026-08-25/schemas/shopping/permalink.json +68 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/adjustment.json +10 -4
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/attribution.json +2 -2
- data/schemas/2026-08-25/schemas/shopping/types/availability.json +17 -0
- data/schemas/2026-08-25/schemas/shopping/types/business_fulfillment_config.json +37 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/buyer.json +2 -2
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/category.json +2 -2
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/detail_option_value.json +3 -3
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/expectation.json +6 -10
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/fulfillment.json +4 -5
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/fulfillment_available_method.json +3 -8
- data/schemas/2026-08-25/schemas/shopping/types/fulfillment_destination.json +55 -0
- data/schemas/2026-08-25/schemas/shopping/types/fulfillment_destination_filter.json +23 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/fulfillment_event.json +4 -3
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/fulfillment_group.json +3 -3
- data/schemas/2026-08-25/schemas/shopping/types/fulfillment_method.json +118 -0
- data/schemas/2026-08-25/schemas/shopping/types/fulfillment_option.json +46 -0
- data/schemas/2026-08-25/schemas/shopping/types/fulfillment_option_base.json +29 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/input_correlation.json +2 -2
- data/schemas/2026-08-25/schemas/shopping/types/item.json +43 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/line_item.json +7 -6
- data/schemas/2026-08-25/schemas/shopping/types/location_destination.json +26 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/option_value.json +2 -2
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/order_confirmation.json +2 -2
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/order_line_item.json +12 -9
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/platform_fulfillment_config.json +2 -2
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/product.json +10 -10
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/product_option.json +3 -3
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/rating.json +2 -2
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/search_filters.json +3 -3
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/selected_option.json +2 -2
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/shipping_destination.json +11 -5
- data/schemas/2026-08-25/schemas/shopping/types/unit_price.json +56 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/shopping/types/variant.json +19 -78
- data/schemas/2026-08-25/schemas/transports/a2a_message.json +165 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/transports/embedded_config.json +2 -2
- data/schemas/2026-08-25/schemas/transports/embedded_message.json +69 -0
- data/schemas/2026-08-25/schemas/transports/jsonrpc.json +136 -0
- data/schemas/2026-08-25/schemas/transports/mcp_tool_call.json +143 -0
- data/schemas/{2026-04-08 → 2026-08-25}/schemas/ucp.json +73 -23
- data/schemas/2026-08-25/services/common/mcp.openrpc.json +105 -0
- data/schemas/2026-08-25/services/common/rest.openapi.json +328 -0
- data/schemas/2026-08-25/services/payment-actions/embedded.openrpc.json +89 -0
- data/schemas/2026-08-25/services/shopping/embedded.openrpc.json +634 -0
- data/schemas/{2026-04-08 → 2026-08-25}/services/shopping/mcp.openrpc.json +21 -20
- data/schemas/2026-08-25/services/shopping/permalink.openapi.json +136 -0
- data/schemas/2026-08-25/services/shopping/rest.openapi.json +1350 -0
- metadata +125 -71
- data/schemas/2026-04-08/schemas/shopping/catalog_search.json +0 -64
- data/schemas/2026-04-08/schemas/shopping/fulfillment.json +0 -154
- data/schemas/2026-04-08/schemas/shopping/types/available_payment_instrument.json +0 -22
- data/schemas/2026-04-08/schemas/shopping/types/business_fulfillment_config.json +0 -38
- data/schemas/2026-04-08/schemas/shopping/types/context.json +0 -42
- data/schemas/2026-04-08/schemas/shopping/types/fulfillment_destination.json +0 -16
- data/schemas/2026-04-08/schemas/shopping/types/fulfillment_method.json +0 -67
- data/schemas/2026-04-08/schemas/shopping/types/fulfillment_option.json +0 -56
- data/schemas/2026-04-08/schemas/shopping/types/item.json +0 -33
- data/schemas/2026-04-08/schemas/shopping/types/message.json +0 -18
- data/schemas/2026-04-08/schemas/shopping/types/retail_location.json +0 -28
- data/schemas/2026-04-08/schemas/shopping/types/reverse_domain_name.json +0 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a245e863596f643972f10c9be20792055d6bf1d2925b90373571966896ee429a
|
|
4
|
+
data.tar.gz: ad0008e190d5c865e613b616653a7d5dbd5f6b19166f8f71723e57ae70ef7ce0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d9a93b39705265b1095da290e5615ddbfcf3d3ea529d9b5863308ad99819c70b11ed77bc9805444a003b78c61bb418d4faa756617148d74b964b88beb90b5330
|
|
7
|
+
data.tar.gz: c2c95f6b3217ea2c2dc6b86318eaa845677b45c753b707ad2eb17f2ae7599f92fe457f7f82a34d46cfea26f1b5bfa8bc17ff4ee46459c94967c6de5ed6286611
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@ pre-1.0, so APIs may still shift between minor versions.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.14.0] - 2026-10-09
|
|
10
|
+
|
|
11
|
+
Moves the gem to UCP 2026-08-25 (design-log §56-58). Minor-level for a pre-1.0 gem, with breaking config changes below.
|
|
12
|
+
|
|
13
|
+
- **Breaking: `config.payment_handlers` is now a Hash of `reverse-domain-key => [entry, ...]`, each entry carrying an `id`.** Default is `{}` (was an Array). The manifest emits it as UCP 2026-08-25's keyed `payment_handlers` object with date `version`s; an Array no longer works. `config.services` arrays still work: they are keyed by service name and each entry gets a `version`. A services Hash already keyed by name passes through, keeping an entry's own `version`.
|
|
14
|
+
- **Breaking: the manifest emits `keys` (a JWK Set) at the document root; `ucp.signing_keys` is gone.** Anything reading signing keys from `ucp.signing_keys` must read `keys`. Each key needs a `kid`.
|
|
15
|
+
- **Changed: UCP version is 2026-08-25** (manifest, `WireEnvelope`, `SchemaValidator` default). Capabilities are keyed by reverse-domain name with a date `version` and `schema` URL, and the whole manifest validates against `profile.json#/$defs/business_schema`.
|
|
16
|
+
- **Changed: `FulfillmentOption` `description` is sent as a `description.json` object** rather than a bare string, as 2026-08-25 requires.
|
|
17
|
+
- **Removed: the vendored `schemas/2026-04-08/` tree.** `SchemaValidator.new(version: "2026-04-08")` no longer loads; only `schemas/2026-08-25/` ships. Nothing else in the workspace validated against it (`portage-ucp-client` reads remote profiles without vendored schemas, so stores still serving 2026-04-08 keep working).
|
|
18
|
+
|
|
9
19
|
## [0.13.0] - 2026-10-07
|
|
10
20
|
|
|
11
21
|
- **Added: `Support::CheckoutState` can ask the platform about a checkout this process doesn't track.** An adapter may define a private `platform_checkout_order(checkout_id)` that returns the `Order` its platform placed from that checkout, or nil. `#checkout_status` then reports `completed` for an id with no in-process record, the new `#checkout_order` returns its `OrderConfirmation`, and the new `#checkout_from_platform_order` rebuilds a completed `Checkout` from the order when the platform has already dropped the cart. A found order is cached through `#record_checkout_status`/`#record_order_checkout`; no order, no hook, or a lookup error keeps today's `incomplete`. This lets `portage orders reconcile`, which runs in a new process, see a checkout the shopper paid for in the browser (design-log §55). The `Adapter` contract is unchanged. Minor-level.
|
|
@@ -14,8 +14,8 @@ Portage::Ucp.configure do |config|
|
|
|
14
14
|
|
|
15
15
|
# config.signer = MySigner.new
|
|
16
16
|
# config.signing_keys = []
|
|
17
|
-
# config.payment_handlers = []
|
|
18
|
-
# config.services = []
|
|
17
|
+
# config.payment_handlers = {} # { "com.example.pay" => [{ id: "..." }] }
|
|
18
|
+
# config.services = {} # { "dev.ucp.shopping" => [{ transport: "mcp", endpoint: "..." }] }
|
|
19
19
|
# config.mandate_trusted_keys = []
|
|
20
20
|
# config.require_mandate_signature = false
|
|
21
21
|
end
|
|
@@ -4,6 +4,7 @@ module Portage
|
|
|
4
4
|
CATALOG = Portage::Ucp::Capability.new(
|
|
5
5
|
name: "dev.ucp.shopping.catalog",
|
|
6
6
|
version: "1",
|
|
7
|
+
schema: "shopping/catalog_search.json",
|
|
7
8
|
actions: { "search_catalog" => :search_catalog, "get_product" => :get_product,
|
|
8
9
|
"lookup_catalog" => :lookup_catalog }
|
|
9
10
|
)
|
|
@@ -3,7 +3,7 @@ module Portage
|
|
|
3
3
|
# A named, versioned UCP capability (e.g. "dev.ucp.shopping.catalog") mapping
|
|
4
4
|
# UCP action names to the Adapter methods that back them.
|
|
5
5
|
class Capability
|
|
6
|
-
attr_reader :name, :version, :actions
|
|
6
|
+
attr_reader :name, :version, :actions, :schema
|
|
7
7
|
|
|
8
8
|
# `predicate:` is for extension capabilities like
|
|
9
9
|
# dev.ucp.shopping.discount and dev.ucp.shopping.fulfillment that add a
|
|
@@ -11,8 +11,13 @@ module Portage
|
|
|
11
11
|
# there's no dedicated method whose override signals support, so the
|
|
12
12
|
# adapter exposes a boolean method instead and the capability asks it
|
|
13
13
|
# directly rather than inspecting `actions`.
|
|
14
|
-
|
|
14
|
+
#
|
|
15
|
+
# `schema:` is the capability's schema path under a UCP revision's
|
|
16
|
+
# `schemas/` (e.g. "shopping/checkout.json"); the manifest turns it into
|
|
17
|
+
# the `schema` URL 2026-08-25 business profiles require.
|
|
18
|
+
def initialize(name:, version:, actions:, predicate: nil, schema: nil)
|
|
15
19
|
@name = name
|
|
20
|
+
@schema = schema
|
|
16
21
|
@version = version
|
|
17
22
|
@actions = actions
|
|
18
23
|
@predicate = predicate
|
|
@@ -51,7 +51,7 @@ module Portage
|
|
|
51
51
|
@authenticator = UnconfiguredAuthenticator.new
|
|
52
52
|
@rate_limiter = NullRateLimiter.new
|
|
53
53
|
@logger = Logger.new($stdout)
|
|
54
|
-
@payment_handlers =
|
|
54
|
+
@payment_handlers = {}
|
|
55
55
|
@signing_keys = []
|
|
56
56
|
@services = []
|
|
57
57
|
@require_mandate_signature = false
|
data/lib/portage/ucp/manifest.rb
CHANGED
|
@@ -6,11 +6,12 @@ module Portage
|
|
|
6
6
|
# Builds the /.well-known/ucp discovery document: protocol version, the
|
|
7
7
|
# business's advertised capabilities (only those the Adapter overrides —
|
|
8
8
|
# see Capability#advertised_for?), payment handlers, signing keys, and the
|
|
9
|
-
# services
|
|
9
|
+
# services (transport + endpoint, e.g. {transport: "mcp", endpoint:
|
|
10
10
|
# "https://..."}) a client needs to find where to actually connect.
|
|
11
11
|
# Signing keys are never generated here — see §9, consumer-provided only.
|
|
12
12
|
class Manifest
|
|
13
|
-
UCP_VERSION = "2026-
|
|
13
|
+
UCP_VERSION = "2026-08-25".freeze
|
|
14
|
+
SERVICE_KEY = "dev.ucp.shopping".freeze
|
|
14
15
|
|
|
15
16
|
# @param signer [#kid, #sign] optional. Consumer-provided — the gem never
|
|
16
17
|
# generates or stores keys itself (§9). `sign(canonical_json_string)`
|
|
@@ -35,26 +36,47 @@ module Portage
|
|
|
35
36
|
# capability name. That is the shape live Shopify UCP rollouts (Casper,
|
|
36
37
|
# Allbirds, Glossier, and 34+ others) serve under their own manifest
|
|
37
38
|
# "version": "2026-08-25", and the shape portage-ucp-client's
|
|
38
|
-
# Client.discover reads.
|
|
39
|
-
#
|
|
39
|
+
# Client.discover reads. As of 2026-08-25 the JWK Set is `keys` beside
|
|
40
|
+
# `ucp` (not `ucp.signing_keys`), and `services`, `capabilities` and
|
|
41
|
+
# `payment_handlers` are objects keyed by reverse-domain name whose
|
|
42
|
+
# entries carry a date `version` (capabilities also a `schema` URL,
|
|
43
|
+
# handlers an `id`). `services` still accepts the old bare array of
|
|
44
|
+
# entries, filed under SERVICE_KEY; `payment_handlers` must already be
|
|
45
|
+
# a Hash of key => [entry, ...].
|
|
40
46
|
def to_h
|
|
41
47
|
ucp = {
|
|
42
48
|
version: UCP_VERSION,
|
|
43
49
|
business: @business,
|
|
44
|
-
services:
|
|
50
|
+
services: keyed(service_hash),
|
|
45
51
|
capabilities: capability_hash,
|
|
46
|
-
payment_handlers: @payment_handlers
|
|
47
|
-
signing_keys: @signing_keys
|
|
52
|
+
payment_handlers: keyed(@payment_handlers)
|
|
48
53
|
}
|
|
49
54
|
ucp = ucp.merge(signature: sign(ucp)) if @signer
|
|
50
55
|
|
|
51
|
-
{ ucp: ucp }
|
|
56
|
+
{ ucp: ucp, keys: @signing_keys }
|
|
52
57
|
end
|
|
53
58
|
|
|
54
59
|
private
|
|
55
60
|
|
|
56
61
|
def capability_hash
|
|
57
|
-
@registry.advertised(@adapter).to_h
|
|
62
|
+
@registry.advertised(@adapter).to_h do |capability|
|
|
63
|
+
entry = { version: UCP_VERSION }
|
|
64
|
+
entry[:schema] = "https://ucp.dev/#{UCP_VERSION}/schemas/#{capability.schema}" if capability.schema
|
|
65
|
+
[capability.name, [entry]]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def service_hash
|
|
70
|
+
return @services if @services.is_a?(Hash)
|
|
71
|
+
|
|
72
|
+
@services.empty? ? {} : { SERVICE_KEY => @services }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Every entry needs a version; the caller's own wins.
|
|
76
|
+
def keyed(entries_by_key)
|
|
77
|
+
entries_by_key.to_h do |key, entries|
|
|
78
|
+
[key, [entries].flatten(1).map { |entry| { version: UCP_VERSION }.merge(entry) }]
|
|
79
|
+
end
|
|
58
80
|
end
|
|
59
81
|
|
|
60
82
|
def sign(payload)
|
|
@@ -9,12 +9,12 @@ module Portage
|
|
|
9
9
|
# is the CI-safe equivalent).
|
|
10
10
|
#
|
|
11
11
|
# The vendored tree mirrors https://ucp.dev/<version>/... path-for-path
|
|
12
|
-
# (schemas/2026-
|
|
13
|
-
# https://ucp.dev/2026-
|
|
12
|
+
# (schemas/2026-08-25/schemas/shopping/cart.json <->
|
|
13
|
+
# https://ucp.dev/2026-08-25/schemas/shopping/cart.json), so every $ref
|
|
14
14
|
# inside a vendored document — however deeply nested — resolves to another
|
|
15
15
|
# vendored file with a single prefix rewrite, no network access needed.
|
|
16
16
|
class SchemaValidator
|
|
17
|
-
def initialize(version: "2026-
|
|
17
|
+
def initialize(version: "2026-08-25", root: File.join(__dir__, "..", "..", "..", "schemas"))
|
|
18
18
|
@base_url = "https://ucp.dev/#{version}/"
|
|
19
19
|
@base_dir = File.expand_path(File.join(root, version))
|
|
20
20
|
end
|
|
@@ -272,6 +272,8 @@ module Portage
|
|
|
272
272
|
|
|
273
273
|
# schemas/shopping/types/fulfillment_option.json — a single priced choice
|
|
274
274
|
# within a FulfillmentGroup (e.g. "Standard Shipping $5", "Express $15").
|
|
275
|
+
# `description` is a common/types/description.json object
|
|
276
|
+
# ({"plain"/"html"/"markdown" => ...}); a bare String is sent as `plain`.
|
|
275
277
|
FulfillmentOption = Data.define(:id, :title, :totals, :description, :carrier, :earliest_fulfillment_time,
|
|
276
278
|
:latest_fulfillment_time) do
|
|
277
279
|
def initialize(id:, title:, totals:, description: nil, carrier: nil, earliest_fulfillment_time: nil,
|
|
@@ -281,7 +283,7 @@ module Portage
|
|
|
281
283
|
|
|
282
284
|
def to_wire_h
|
|
283
285
|
h = { "id" => id, "title" => title, "totals" => totals.map(&:to_wire_h) }
|
|
284
|
-
h["description"] = description if description
|
|
286
|
+
h["description"] = description.is_a?(String) ? { "plain" => description } : description if description
|
|
285
287
|
h["carrier"] = carrier if carrier
|
|
286
288
|
h["earliest_fulfillment_time"] = earliest_fulfillment_time if earliest_fulfillment_time
|
|
287
289
|
h["latest_fulfillment_time"] = latest_fulfillment_time if latest_fulfillment_time
|
data/lib/portage/ucp/version.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Portage
|
|
|
6
6
|
# capability's minimum envelope shape live in one place, not duplicated
|
|
7
7
|
# across value objects.
|
|
8
8
|
module WireEnvelope
|
|
9
|
-
SPEC_VERSION = "2026-
|
|
9
|
+
SPEC_VERSION = "2026-08-25".freeze
|
|
10
10
|
|
|
11
11
|
ENVELOPES = {
|
|
12
12
|
"dev.ucp.shopping.cart" => -> { { "version" => SPEC_VERSION } },
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://ucp.dev/2026-
|
|
3
|
+
"$id": "https://ucp.dev/2026-08-25/schemas/capability.json",
|
|
4
4
|
"title": "UCP Capability",
|
|
5
5
|
"description": "Schema for UCP capabilities and extensions. Extensions are capabilities with an 'extends' field. Uses reverse-domain naming for governance.",
|
|
6
6
|
"$defs": {
|
|
7
7
|
"base": {
|
|
8
8
|
"allOf": [
|
|
9
9
|
{
|
|
10
|
-
"$ref": "https://ucp.dev/2026-
|
|
10
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/ucp.json#/$defs/entity"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
"type": "object",
|
|
@@ -15,14 +15,12 @@
|
|
|
15
15
|
"extends": {
|
|
16
16
|
"oneOf": [
|
|
17
17
|
{
|
|
18
|
-
"
|
|
19
|
-
"pattern": "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$"
|
|
18
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/reverse_domain_name.json"
|
|
20
19
|
},
|
|
21
20
|
{
|
|
22
21
|
"type": "array",
|
|
23
22
|
"items": {
|
|
24
|
-
"
|
|
25
|
-
"pattern": "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$"
|
|
23
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/reverse_domain_name.json"
|
|
26
24
|
},
|
|
27
25
|
"minItems": 1
|
|
28
26
|
}
|
|
@@ -50,10 +48,15 @@
|
|
|
50
48
|
},
|
|
51
49
|
"business_schema": {
|
|
52
50
|
"title": "Capability (Business Schema)",
|
|
53
|
-
"description": "Capability
|
|
51
|
+
"description": "Capability declaration for business/merchant discovery. Requires the `schema` URL so platforms can fetch and compose it during negotiation; may also include business-specific config overrides.",
|
|
54
52
|
"allOf": [
|
|
55
53
|
{
|
|
56
54
|
"$ref": "#/$defs/base"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"required": [
|
|
58
|
+
"schema"
|
|
59
|
+
]
|
|
57
60
|
}
|
|
58
61
|
]
|
|
59
62
|
},
|
|
@@ -67,4 +70,4 @@
|
|
|
67
70
|
]
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
|
-
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://ucp.dev/2026-08-25/schemas/common/identity_linking.json",
|
|
4
|
+
"name": "dev.ucp.common.identity_linking",
|
|
5
|
+
"title": "Identity Linking",
|
|
6
|
+
"description": "Capability schema for identity linking. Businesses declare the user-authenticated scopes they offer in a flat 'scopes' map. Each key is the OAuth scope string as it appears on the wire ('{capability}:{scope}', e.g. 'dev.ucp.shopping.order:read'). Scope presence implies that the corresponding operations require user authentication. Operations not gated by any listed scope operate at whatever access level the business permits; UCP does not prescribe a default.",
|
|
7
|
+
"$defs": {
|
|
8
|
+
"scope_policy": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"title": "Scope Policy",
|
|
11
|
+
"description": "Per-scope policy and metadata — auth constraints (e.g. min_acr, max_token_age), declarative metadata (e.g. claims produced, consent descriptions), or any other scope-specific configuration. An empty object means user authentication is required with no additional policy. Open for non-breaking extension.",
|
|
12
|
+
"properties": {
|
|
13
|
+
"description": {
|
|
14
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/description.json",
|
|
15
|
+
"description": "Optional human-readable description of the scope that platforms can use to present and explain context (requirement and value) to the user."
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"additionalProperties": true
|
|
19
|
+
},
|
|
20
|
+
"scope_token": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "OAuth scope string formed by joining a capability name and a scope name with a colon: '{capability}:{scope}', e.g. 'dev.ucp.shopping.order:read'. Capability names use reverse-DNS naming; scope names denote the permission granted, defined by each capability's spec (e.g. 'read', 'manage', 'create'). Platforms request these strings verbatim in OAuth 'scope' parameters; issued tokens carry them in the 'scope' claim.",
|
|
23
|
+
"pattern": "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+:[a-z][a-z0-9_]*$"
|
|
24
|
+
},
|
|
25
|
+
"provider": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"title": "Identity Provider",
|
|
28
|
+
"description": "A trusted identity provider for delegated authentication, keyed by the 'type' discriminator. 'oauth2' denotes an OAuth 2.0 / OIDC authorization server. Future versions MAY define additional types (e.g. wallet attestation) as non-breaking extensions; platforms MUST treat entries whose 'type' they do not support as filtered out (see Provider Selection).",
|
|
29
|
+
"required": [
|
|
30
|
+
"type"
|
|
31
|
+
],
|
|
32
|
+
"properties": {
|
|
33
|
+
"type": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Provider mechanism discriminator. 'oauth2' for OAuth 2.0 / OIDC authorization servers. Additional values MAY be defined by future versions; the value is an open string, not a closed enum, so unrecognized types remain valid and are filtered at runtime."
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"allOf": [
|
|
39
|
+
{
|
|
40
|
+
"if": {
|
|
41
|
+
"properties": {
|
|
42
|
+
"type": {
|
|
43
|
+
"const": "oauth2"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"then": {
|
|
48
|
+
"required": [
|
|
49
|
+
"auth_url"
|
|
50
|
+
],
|
|
51
|
+
"properties": {
|
|
52
|
+
"auth_url": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"format": "uri",
|
|
55
|
+
"description": "Base URL for authorization server metadata discovery. Platforms resolve metadata via RFC 8414 (/.well-known/oauth-authorization-server) with OIDC fallback (/.well-known/openid-configuration) on 404."
|
|
56
|
+
},
|
|
57
|
+
"required_claims": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": {
|
|
60
|
+
"type": "string"
|
|
61
|
+
},
|
|
62
|
+
"uniqueItems": true,
|
|
63
|
+
"description": "OIDC Core §5.1 claim names the business requires in the JWT authorization grant from this provider (e.g. 'email'). Optional pre-filter hint: platforms SHOULD skip this provider during selection when their upstream identity lacks any of the listed claim names. Reactive enforcement at the token endpoint remains mandatory regardless; this field expresses claim presence only, not value constraints."
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"additionalProperties": true
|
|
70
|
+
},
|
|
71
|
+
"dev.ucp.common.identity_linking": {
|
|
72
|
+
"platform_schema": {
|
|
73
|
+
"title": "Identity Linking (Platform)",
|
|
74
|
+
"description": "Platform-level identity linking capability declaration. Platforms advertise support for identity linking; no auth-specific config is required.",
|
|
75
|
+
"allOf": [
|
|
76
|
+
{
|
|
77
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/capability.json#/$defs/platform_schema"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"business_schema": {
|
|
82
|
+
"title": "Identity Linking (Business)",
|
|
83
|
+
"description": "Business-level identity linking configuration. Businesses declare the user-authenticated scopes they offer in 'config.scopes'.",
|
|
84
|
+
"allOf": [
|
|
85
|
+
{
|
|
86
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/capability.json#/$defs/business_schema"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"type": "object",
|
|
90
|
+
"required": [
|
|
91
|
+
"config"
|
|
92
|
+
],
|
|
93
|
+
"properties": {
|
|
94
|
+
"config": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"required": [
|
|
97
|
+
"scopes"
|
|
98
|
+
],
|
|
99
|
+
"properties": {
|
|
100
|
+
"providers": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"description": "Map of trusted external identity providers keyed by reverse-domain identifier. Each key maps to an array of mechanism entries — an IdP namespace MAY offer multiple token acquisition mechanisms. Declares which upstream IdPs the business will accept JWT bearer assertions from for the Accelerated IdP Flow (chaining via RFC 8693 + RFC 7523). This field is additive: direct OAuth against the business domain via RFC 8414 discovery is always available regardless of 'providers' content. Businesses MUST NOT list their own authorization server here — chaining-to-self is degenerate, and direct OAuth covers that path. When absent, empty, or when no listed mechanism is supported by the platform, platforms run direct OAuth on the business domain.",
|
|
103
|
+
"propertyNames": {
|
|
104
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/reverse_domain_name.json"
|
|
105
|
+
},
|
|
106
|
+
"additionalProperties": {
|
|
107
|
+
"type": "array",
|
|
108
|
+
"items": {
|
|
109
|
+
"$ref": "#/$defs/provider"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"scopes": {
|
|
114
|
+
"type": "object",
|
|
115
|
+
"description": "Map of user-authenticated scopes offered by this business. Each key is an OAuth scope string formed as '{capability}:{scope}' (e.g. 'dev.ucp.shopping.order:read'). Scope presence in this map declares that the corresponding operations require a user identity token. Operations not gated by any listed scope operate at whatever access level the business permits; UCP does not prescribe a default. Each value is a per-scope policy object (empty object means user auth required with no additional policy).",
|
|
116
|
+
"propertyNames": {
|
|
117
|
+
"$ref": "#/$defs/scope_token"
|
|
118
|
+
},
|
|
119
|
+
"additionalProperties": {
|
|
120
|
+
"$ref": "#/$defs/scope_policy"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"additionalProperties": true
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"version": "2026-08-25"
|
|
133
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://ucp.dev/2026-08-25/schemas/common/location_lookup.json",
|
|
4
|
+
"name": "dev.ucp.common.location.lookup",
|
|
5
|
+
"title": "Location Lookup",
|
|
6
|
+
"description": "Location lookup by identifiers. Supports batch retrieval and single-location detail.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"$defs": {
|
|
9
|
+
"lookup_location": {
|
|
10
|
+
"description": "Location with required correlation metadata for lookup responses.",
|
|
11
|
+
"allOf": [
|
|
12
|
+
{
|
|
13
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location.json"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "object",
|
|
17
|
+
"required": [
|
|
18
|
+
"inputs"
|
|
19
|
+
],
|
|
20
|
+
"properties": {
|
|
21
|
+
"inputs": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": [
|
|
26
|
+
"id"
|
|
27
|
+
],
|
|
28
|
+
"properties": {
|
|
29
|
+
"id": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "The identifier exactly as supplied in the lookup request.",
|
|
32
|
+
"ucp_request": "omit"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"minItems": 1,
|
|
37
|
+
"description": "Which request identifiers resolved to this Location. Each entry preserves one identifier exactly as supplied in the request.",
|
|
38
|
+
"ucp_request": "omit"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"lookup_request": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"description": "Request body for batch location lookup. The Business resolves and deduplicates `ids` before applying `distance`, `serves`, and every supplied `filters` predicate; all structured predicates combine with AND.",
|
|
47
|
+
"required": [
|
|
48
|
+
"ids"
|
|
49
|
+
],
|
|
50
|
+
"properties": {
|
|
51
|
+
"ids": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"items": {
|
|
54
|
+
"type": "string"
|
|
55
|
+
},
|
|
56
|
+
"minItems": 1,
|
|
57
|
+
"description": "Identifiers of the Locations to look up. The Business MUST support canonical `Location.id` values and MAY support secondary or alias identifiers."
|
|
58
|
+
},
|
|
59
|
+
"distance": {
|
|
60
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location_distance.json",
|
|
61
|
+
"description": "Optional explicit-center radius predicate applied after ID resolution. It combines with `serves` and every supplied `filters` predicate using AND.",
|
|
62
|
+
"ucp_request": "optional"
|
|
63
|
+
},
|
|
64
|
+
"serves": {
|
|
65
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location_serves.json",
|
|
66
|
+
"description": "Optional authoritative service-target predicate applied after ID resolution. It combines with `distance` and every supplied `filters` predicate using AND.",
|
|
67
|
+
"ucp_request": "optional"
|
|
68
|
+
},
|
|
69
|
+
"filters": {
|
|
70
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location_filter.json"
|
|
71
|
+
},
|
|
72
|
+
"context": {
|
|
73
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/context.json"
|
|
74
|
+
},
|
|
75
|
+
"signals": {
|
|
76
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/signals.json"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"lookup_response": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"required": [
|
|
83
|
+
"ucp",
|
|
84
|
+
"locations"
|
|
85
|
+
],
|
|
86
|
+
"properties": {
|
|
87
|
+
"ucp": {
|
|
88
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/ucp.json#/$defs/response_location_schema"
|
|
89
|
+
},
|
|
90
|
+
"locations": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": {
|
|
93
|
+
"$ref": "#/$defs/lookup_location"
|
|
94
|
+
},
|
|
95
|
+
"description": "Locations matching the requested identifiers and refinements. May contain fewer Locations if some identifiers do not resolve or their resolved Locations are filtered out, or more if one identifier resolves to multiple Locations. When multiple identifiers resolve to the same Location, one returned Location carries all corresponding `inputs` entries."
|
|
96
|
+
},
|
|
97
|
+
"messages": {
|
|
98
|
+
"type": "array",
|
|
99
|
+
"items": {
|
|
100
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/message.json"
|
|
101
|
+
},
|
|
102
|
+
"description": "Errors, warnings, or informational messages about the requested Locations, including `batch_limit_applied` when the Business processes only its configured maximum number of identifiers."
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"version": "2026-08-25"
|
|
108
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://ucp.dev/2026-08-25/schemas/common/location_search.json",
|
|
4
|
+
"name": "dev.ucp.common.location.search",
|
|
5
|
+
"title": "Location Search",
|
|
6
|
+
"description": "Location search capability. Supports natural language queries, distance and serviceability relations, structured filtering including current item availability, and pagination.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"$defs": {
|
|
9
|
+
"search_request": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"description": "Request body for location search. The `distance` and `serves` relations and every supplied `filters` predicate combine with AND; `query` does not relax them.",
|
|
12
|
+
"properties": {
|
|
13
|
+
"query": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Free-text search query for natural language location search (e.g., 'restaurants near me that deliver', 'hotels with pool')."
|
|
16
|
+
},
|
|
17
|
+
"context": {
|
|
18
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/context.json"
|
|
19
|
+
},
|
|
20
|
+
"signals": {
|
|
21
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/signals.json"
|
|
22
|
+
},
|
|
23
|
+
"distance": {
|
|
24
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location_distance.json",
|
|
25
|
+
"description": "Optional explicit-center radius predicate. When present, it combines with `serves` and every supplied `filters` predicate using AND.",
|
|
26
|
+
"ucp_request": "optional"
|
|
27
|
+
},
|
|
28
|
+
"serves": {
|
|
29
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location_serves.json",
|
|
30
|
+
"description": "Optional authoritative service-target predicate. When present, it combines with `distance` and every supplied `filters` predicate using AND.",
|
|
31
|
+
"ucp_request": "optional"
|
|
32
|
+
},
|
|
33
|
+
"filters": {
|
|
34
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location_filter.json"
|
|
35
|
+
},
|
|
36
|
+
"pagination": {
|
|
37
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/pagination.json#/$defs/request"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"search_response": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"required": [
|
|
44
|
+
"ucp",
|
|
45
|
+
"locations"
|
|
46
|
+
],
|
|
47
|
+
"properties": {
|
|
48
|
+
"ucp": {
|
|
49
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/ucp.json#/$defs/response_location_schema"
|
|
50
|
+
},
|
|
51
|
+
"locations": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"items": {
|
|
54
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/location.json"
|
|
55
|
+
},
|
|
56
|
+
"description": "Locations matching the search criteria."
|
|
57
|
+
},
|
|
58
|
+
"pagination": {
|
|
59
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/pagination.json#/$defs/response"
|
|
60
|
+
},
|
|
61
|
+
"messages": {
|
|
62
|
+
"type": "array",
|
|
63
|
+
"items": {
|
|
64
|
+
"$ref": "https://ucp.dev/2026-08-25/schemas/common/types/message.json"
|
|
65
|
+
},
|
|
66
|
+
"description": "Errors, warnings, or informational messages about the search results."
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"version": "2026-08-25"
|
|
72
|
+
}
|