portage-ucp 0.14.0 → 0.15.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 +4 -0
- data/lib/portage/ucp/adapter.rb +1 -1
- data/lib/portage/ucp/security/signature.rb +1 -1
- data/lib/portage/ucp/value_objects.rb +28 -12
- data/lib/portage/ucp/version.rb +1 -1
- metadata +30 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3030cd7b510d8e0e829878dd48ab11fd18f70e0d0e5cac5107852ead26a0077c
|
|
4
|
+
data.tar.gz: 7e6abed9cd7ea40da3ee5f8681ec69f80a6f8c852e8956901f4fce1b383816da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c4dddb8b6aaeaa674d270400287420f3bcbbfc028c8d38b9482fe53fe2cb47b493711cd7fffe50051b892b49f720f4332ba0e3af89fe595df9d46cdf80c5306
|
|
7
|
+
data.tar.gz: 5b1c1ee5a21fae8d7c8821c43820bcdcca15f54001e9d6e25af3b4916965da69a1bedb144faadb06ec222c11a59d3cd7e60c753579a4d8931924f51e62f06b78
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,10 @@ pre-1.0, so APIs may still shift between minor versions.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.15.0] - 2026-10-13
|
|
10
|
+
|
|
11
|
+
- **Added: optional `policies:` on `Cart`, `Checkout`, `Order`, `Product`, `CatalogSearchResult` and `ProductDetail`** (UCP 2026-08-25 `policies[]`). An array of `policy.json` hashes (`type` and `description` required; `applies_to` and `url` optional), default `[]`, omitted from the wire payload when empty. `portage-ucp-shopify` 0.7.0 supplies it (design-log §60).
|
|
12
|
+
|
|
9
13
|
## [0.14.0] - 2026-10-09
|
|
10
14
|
|
|
11
15
|
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.
|
data/lib/portage/ucp/adapter.rb
CHANGED
|
@@ -105,7 +105,7 @@ module Portage
|
|
|
105
105
|
|
|
106
106
|
# --- Reorder (app.portage-ucp.reorder — Portage extension, not part of
|
|
107
107
|
# the UCP spec: dev.ucp.dev has no reorder/cart-hydration capability as
|
|
108
|
-
# of the 2026-
|
|
108
|
+
# of the 2026-08-25 spec) ---
|
|
109
109
|
# Hydrates a cart from a previous order's line items so a caller doesn't
|
|
110
110
|
# have to re-walk get_order + create_cart itself. Re-checks each item's
|
|
111
111
|
# current price/availability rather than replaying the order's snapshot
|
|
@@ -7,7 +7,7 @@ module Portage
|
|
|
7
7
|
module Security
|
|
8
8
|
# Verifies that an inbound agent request carries a valid RFC 9421 HTTP
|
|
9
9
|
# Message Signature, per UCP's own signature spec
|
|
10
|
-
# (ucp.dev/2026-
|
|
10
|
+
# (ucp.dev/2026-08-25/specification/signatures/, pinned 2026-09-15 —
|
|
11
11
|
# this is the piece §22 of the design log flagged as unresearched
|
|
12
12
|
# before writing code, now checked against the live spec rather than
|
|
13
13
|
# guessed). This is a distinct concern from three other signing
|
|
@@ -115,9 +115,10 @@ module Portage
|
|
|
115
115
|
# (Shopify/Wix metafields etc.) — see Portage::Ucp::Shopify.configure's
|
|
116
116
|
# metadata_field.
|
|
117
117
|
Product = Data.define(:id, :title, :description, :price_range, :variants, :handle, :url, :categories,
|
|
118
|
-
:list_price_range, :media, :options, :tags, :metadata, :rating) do
|
|
118
|
+
:list_price_range, :media, :options, :tags, :metadata, :rating, :policies) do
|
|
119
119
|
def initialize(id:, title:, description:, price_range:, variants:, handle: nil, url: nil, categories: [],
|
|
120
|
-
list_price_range: nil, media: [], options: [], tags: [], metadata: nil, rating: nil
|
|
120
|
+
list_price_range: nil, media: [], options: [], tags: [], metadata: nil, rating: nil,
|
|
121
|
+
policies: [])
|
|
121
122
|
super
|
|
122
123
|
end
|
|
123
124
|
|
|
@@ -135,6 +136,7 @@ module Portage
|
|
|
135
136
|
h["media"] = media.map(&:to_wire_h) unless media.empty?
|
|
136
137
|
h["options"] = options.map(&:to_wire_h) unless options.empty?
|
|
137
138
|
h["tags"] = tags unless tags.empty?
|
|
139
|
+
h["policies"] = policies unless policies.empty?
|
|
138
140
|
h
|
|
139
141
|
end
|
|
140
142
|
end
|
|
@@ -144,12 +146,13 @@ module Portage
|
|
|
144
146
|
# isn't schema-conformant (search_response requires `ucp` + `products` at
|
|
145
147
|
# the top level, not a bare array). `messages` entries are left as plain
|
|
146
148
|
# wire-shaped hashes, same rationale as Variant#barcodes above.
|
|
147
|
-
CatalogSearchResult = Data.define(:products, :messages) do
|
|
148
|
-
def initialize(products:, messages: []) = super
|
|
149
|
+
CatalogSearchResult = Data.define(:products, :messages, :policies) do
|
|
150
|
+
def initialize(products:, messages: [], policies: []) = super
|
|
149
151
|
|
|
150
152
|
def to_wire_h
|
|
151
153
|
h = { "products" => products.map(&:to_wire_h) }
|
|
152
154
|
h["messages"] = messages unless messages.empty?
|
|
155
|
+
h["policies"] = policies unless policies.empty?
|
|
153
156
|
h
|
|
154
157
|
end
|
|
155
158
|
end
|
|
@@ -161,8 +164,14 @@ module Portage
|
|
|
161
164
|
# extension (interactive variant narrowing) — Adapter#get_product's
|
|
162
165
|
# signature has no `selected:`/`preferences:` params to source it from
|
|
163
166
|
# yet; unresearched, same status as design-log §16's other backlog items.
|
|
164
|
-
ProductDetail = Data.define(:product) do
|
|
165
|
-
def
|
|
167
|
+
ProductDetail = Data.define(:product, :policies) do
|
|
168
|
+
def initialize(product:, policies: []) = super
|
|
169
|
+
|
|
170
|
+
def to_wire_h
|
|
171
|
+
h = { "product" => product.to_wire_h }
|
|
172
|
+
h["policies"] = policies unless policies.empty?
|
|
173
|
+
h
|
|
174
|
+
end
|
|
166
175
|
end
|
|
167
176
|
|
|
168
177
|
# One cost-breakdown entry (schemas/shopping/types/total.json). `amount` is a
|
|
@@ -198,6 +207,10 @@ module Portage
|
|
|
198
207
|
end
|
|
199
208
|
end
|
|
200
209
|
|
|
210
|
+
# `policies` (cart/checkout/order/catalog responses and products) is the
|
|
211
|
+
# 2026-08-25 policy.json array (return/warranty terms), optional and omitted
|
|
212
|
+
# when empty. Entries stay wire-shaped hashes (`type` and `description` are
|
|
213
|
+
# required, `applies_to`/`url` optional), same posture as `messages`.
|
|
201
214
|
# schemas/shopping/types/link.json
|
|
202
215
|
Link = Data.define(:type, :url, :title) do
|
|
203
216
|
def initialize(type:, url:, title: nil) = super
|
|
@@ -380,13 +393,14 @@ module Portage
|
|
|
380
393
|
# `discounts` is the dev.ucp.shopping.discount extension (optional on both
|
|
381
394
|
# cart.json and its own schema) — omitted from the wire payload when empty,
|
|
382
395
|
# same as Order#adjustments.
|
|
383
|
-
Cart = Data.define(:id, :line_items, :currency, :totals, :discounts) do
|
|
384
|
-
def initialize(id:, line_items:, currency:, totals:, discounts: Discounts.new) = super
|
|
396
|
+
Cart = Data.define(:id, :line_items, :currency, :totals, :discounts, :policies) do
|
|
397
|
+
def initialize(id:, line_items:, currency:, totals:, discounts: Discounts.new, policies: []) = super
|
|
385
398
|
|
|
386
399
|
def to_wire_h
|
|
387
400
|
h = { "id" => id, "line_items" => line_items.map(&:to_wire_h), "currency" => currency,
|
|
388
401
|
"totals" => totals.map(&:to_wire_h) }
|
|
389
402
|
h["discounts"] = discounts.to_wire_h unless discounts.empty?
|
|
403
|
+
h["policies"] = policies unless policies.empty?
|
|
390
404
|
h
|
|
391
405
|
end
|
|
392
406
|
end
|
|
@@ -415,9 +429,9 @@ module Portage
|
|
|
415
429
|
# omitted from the wire payload when empty), same posture as
|
|
416
430
|
# Order#adjustments.
|
|
417
431
|
Checkout = Data.define(:id, :status, :line_items, :currency, :totals, :links, :order, :discounts,
|
|
418
|
-
:fulfillment) do
|
|
432
|
+
:fulfillment, :policies) do
|
|
419
433
|
def initialize(id:, status:, line_items:, currency:, totals:, links:, order: nil, discounts: Discounts.new,
|
|
420
|
-
fulfillment: CheckoutFulfillment.new)
|
|
434
|
+
fulfillment: CheckoutFulfillment.new, policies: [])
|
|
421
435
|
super
|
|
422
436
|
end
|
|
423
437
|
|
|
@@ -427,6 +441,7 @@ module Portage
|
|
|
427
441
|
h["order"] = order.to_wire_h if order
|
|
428
442
|
h["discounts"] = discounts.to_wire_h unless discounts.empty?
|
|
429
443
|
h["fulfillment"] = fulfillment.to_wire_h unless fulfillment.empty?
|
|
444
|
+
h["policies"] = policies unless policies.empty?
|
|
430
445
|
h
|
|
431
446
|
end
|
|
432
447
|
end
|
|
@@ -508,9 +523,9 @@ module Portage
|
|
|
508
523
|
# line_items/fulfillment/currency/totals. `adjustments` is optional —
|
|
509
524
|
# omitted from the wire payload when empty.
|
|
510
525
|
Order = Data.define(:id, :checkout_id, :permalink_url, :line_items, :fulfillment, :currency, :totals,
|
|
511
|
-
:adjustments) do
|
|
526
|
+
:adjustments, :policies) do
|
|
512
527
|
def initialize(id:, checkout_id:, permalink_url:, line_items:, fulfillment:, currency:, totals:,
|
|
513
|
-
adjustments: [])
|
|
528
|
+
adjustments: [], policies: [])
|
|
514
529
|
super
|
|
515
530
|
end
|
|
516
531
|
|
|
@@ -519,6 +534,7 @@ module Portage
|
|
|
519
534
|
"line_items" => line_items.map(&:to_wire_h), "fulfillment" => fulfillment.to_wire_h,
|
|
520
535
|
"currency" => currency, "totals" => totals.map(&:to_wire_h) }
|
|
521
536
|
h["adjustments"] = adjustments.map(&:to_wire_h) unless adjustments.empty?
|
|
537
|
+
h["policies"] = policies unless policies.empty?
|
|
522
538
|
h
|
|
523
539
|
end
|
|
524
540
|
end
|
data/lib/portage/ucp/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: portage-ucp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tom Whitbread
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0.2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bigdecimal
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.1'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.1'
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: json_schemer
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -38,6 +52,20 @@ dependencies:
|
|
|
38
52
|
- - "~>"
|
|
39
53
|
- !ruby/object:Gem::Version
|
|
40
54
|
version: '2.5'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: logger
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.5'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.5'
|
|
41
69
|
- !ruby/object:Gem::Dependency
|
|
42
70
|
name: mcp
|
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|