@01.software/sdk 0.40.0 → 0.41.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,492 @@
1
+ # @01.software/sdk
2
+
3
+ ## 0.41.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 02d271b: Add `projectProductToListingShape(product)` — a pure, non-lossy adapter that
8
+ turns a product read from the raw `collections.from('products').find()` escape
9
+ hatch into the listing shape the SDK builders consume. A raw/public product
10
+ already carries `priceRange`, `availableForSale`, and
11
+ `selectedOrFirstAvailableVariant` but has no `featuredImage`; the adapter fills
12
+ it from the first gallery image so SSG/sitemap consumers can feed
13
+ `buildProductListingGroupsByOption` / `buildProductListingCard` without
14
+ hand-rolling the projection.
15
+ - eb6a4aa: Add `getVariantAvailableForSale(variant)` and `getVariantAvailableStock(variant)`
16
+ pure helpers to the root entry. They expose the SDK's server-equivalent variant
17
+ sellability rule (`isActive && (isUnlimited || stock - reservedStock > 0)`) and a
18
+ Shopify-style `quantityAvailable` number (`max(0, stock - reservedStock)`, or
19
+ `null` when unlimited), so storefronts can compute `availableForSale` without
20
+ re-implementing the check or shipping raw `stock`/`reservedStock` to the browser.
21
+
22
+ ### Patch Changes
23
+
24
+ - 1c93448: Ship `MIGRATION.md` and `CHANGELOG.md` in the published npm tarball. The
25
+ `files` field previously included only `dist`, so the migration docs referenced
26
+ by the release notes were absent from the installed package. The README
27
+ changelog section now points at the shipped `CHANGELOG.md` / `MIGRATION.md`.
28
+
29
+ ## 0.40.0
30
+
31
+ ### Minor Changes
32
+
33
+ - 85abdd1: BREAKING (0.x minor): Remove legacy `CustomerAddress.isDefault` from generated SDK Payload types. Customer default shipping and billing addresses are now represented only by `Customer.defaultShippingAddress` and `Customer.defaultBillingAddress`.
34
+ - 3c3cb1f: **BREAKING (0.x minor)** — expose Shopify-shaped product listing fields (#1207).
35
+
36
+ The internal `listing` projection has been replaced by Shopify-aligned top-level
37
+ fields on `ProductDetail` and `ProductDetailCatalog`:
38
+ - Removed public exports: `ProductDetailListing`, `ProductDetailCatalogListing`,
39
+ `ProductListingGroupsCatalogListing`.
40
+ - Removed the `listing` field from `ProductDetail` / `ProductDetailCatalog`.
41
+ - Added `featuredImage`, `priceRange` (`ProductPriceRange`), `compareAtPriceRange`
42
+ (`ProductMoneyRange`), `availableForSale`, and `selectedOrFirstAvailableVariant`.
43
+ - `ProductDetailDisplayMediaSource` member `'listing_primary'` renamed to
44
+ `'featured_image'`.
45
+ - `ProductListingPageSort` literals renamed (`'listing.minPrice'` →
46
+ `'priceRange.minVariantPrice.amount'`, etc.).
47
+ - Private-contract helper `resolveListingPrimaryImagePointer` renamed to
48
+ `resolveFeaturedImagePointer`.
49
+ - `ProductUpsertResponse` staleness hint renamed `listingProjectionStale` →
50
+ `productProjectionStale`.
51
+
52
+ See `packages/sdk/MIGRATION.md` (“Shopify-shaped product listing fields (#1207)”)
53
+ for the full consumer migration path.
54
+
55
+ - 31ff635: BREAKING (0.x minor): align product media with Shopify-style gallery ordering. Product listing/detail helpers no longer expose product-level `primaryMediaItemId` or `thumbnail` as canonical inputs; use `images[0]` / `featuredImage` instead.
56
+ - 7b1cfa3: BREAKING (0.x minor): Events range responses now expose the tenant-global calendar as `calendar` instead of `calendars`, and embedded range events use `event.calendar` instead of `event.calendars`. Calendar range filters now accept one `calendar` or `calendarSlug` value to match the singleton event calendar model.
57
+
58
+ ### Patch Changes
59
+
60
+ - 4f1f970: Move `canvas-nodes` and `canvas-edges` out of browser-public collection discovery while keeping them available to server-auth SDK clients.
61
+ - a55bbb2: Checkout/order separation (#1285): when the platform flag
62
+ `CHECKOUT_ORDER_SEPARATION` is on, `checkout()` resolves to a Checkout that is
63
+ promoted to an Order at payment. The public response stays `PublicOrder`-shaped
64
+ via the `projectCheckoutAsOrder` shim. `orderNumber` remains the stable
65
+ cross-window correlation key; pre-payment `id` is checkout-backed until
66
+ promotion, and `status` is projected to the legacy-compatible `pending` value for
67
+ open checkouts. No breaking change; the distinct `PublicCheckout` surface
68
+ remains a deferred follow-up.
69
+ - b4ceb12: Add `placedAt` to the public `Order` type. This write-once timestamp marks when an order was first placed (the first paid transition) and is the placed-date basis for sales reporting. The field is additive and optional, so existing consumers are unaffected.
70
+ - 67f35a7: Expose `returnStatus` on public order responses and document `status` /
71
+ `displayStatus` as deprecated compatibility aliases.
72
+ - 3ce85af: Clarify generated order shipment field descriptions for tenant administrators.
73
+ - 5b7daed: Expose product `storefrontVisibility` in generated SDK Payload types.
74
+ - 645d7d4: Expose `customer-profile-stats` as a browser-readable public collection and type its public profile stats shape.
75
+ - 60063b7: Expose the `refunded` transaction status across SDK and CLI transaction update contracts.
76
+ - 30333d3: Move tenant commerce config into the SDK internal collection registry while keeping storefront collection discovery unchanged.
77
+
78
+ ## 0.39.0
79
+
80
+ ### Minor Changes
81
+
82
+ - 07d3d00: BREAKING (0.x minor): browser publishable-key raw collection reads now reject
83
+ relationship-expanded `depth`, `joins`, or `populate` options before making a
84
+ request. Direct HTTP raw reads with publishable keys return `400` for the same
85
+ contract violation instead of a not-found response.
86
+
87
+ Browser commerce listing-group helpers are catalog-only: `listingPage()` and
88
+ `listingGroups()` use public-safe catalog endpoints, and full listing-group
89
+ responses require server credentials.
90
+
91
+ - 07d3d00: Add `commerce.product.listingPage()` and the matching React Query helper
92
+ surface, including `useProductListingPage()`, for greenfield product listing
93
+ pages.
94
+ - 77eb02f: Add a storefront cache resource helper subpath for product listing/detail SSG and ISR invalidation tags.
95
+
96
+ ### Patch Changes
97
+
98
+ - 52f947a: Add browser-safe storefront content helpers for links and gallery items.
99
+
100
+ ## 0.38.0
101
+
102
+ ### Minor Changes
103
+
104
+ - f6263df: Sanitize public SDK response surfaces and split browser-public collection
105
+ discovery from server-auth collection access.
106
+
107
+ The SDK now routes community post/comment reads through projected public
108
+ endpoints, exposes projected community response types, and removes raw
109
+ customer/order/cart/media/community slugs from browser-public `COLLECTIONS`.
110
+ Server-auth clients continue to address those slugs through
111
+ `SERVER_COLLECTIONS`.
112
+
113
+ The CLI now validates and discovers server-auth collections for authenticated
114
+ agent and CRUD workflows.
115
+
116
+ BREAKING (0.x minor): browser `COLLECTIONS` no longer includes raw
117
+ customer/order/cart/media/community slugs; use `SERVER_COLLECTIONS` or
118
+ `@01.software/sdk/server` for raw server-auth access. Browser publishable-key raw
119
+ collection reads now default SDK calls to `depth=0&joins=false`, and raw
120
+ publishable-key reads require those relationship-expansion defaults. Use shaped
121
+ helpers such as `commerce.product.detail()`, `commerce.cart.*`, community
122
+ helpers, and customer order helpers for populated customer-facing DTOs. Cart and
123
+ customer order methods now return sanitized public DTOs instead of raw Payload
124
+ documents.
125
+
126
+ ### Patch Changes
127
+
128
+ - 0af07b3: Add generated Payload type documentation for Admin collection descriptions.
129
+ - 7ca5b46: Refresh generated Payload SDK types after removing descriptions for retired Console-only collections.
130
+ - 992bf72: Update generated event visibility documentation in SDK payload types to match the hardened public event API contract.
131
+ - b2ce208: Expose structured event recurrence fields in generated SDK event collection types.
132
+ - 1ba77f6: Drop the unreachable order-level `failed` status from the public order types.
133
+
134
+ Order-level payment failure is recorded as `Transaction.status = failed` while
135
+ the order stays `pending`; permanent abandonment uses cancellation. Generated
136
+ SDK Payload types and the public `CancelOrderStatus` union no longer include
137
+ order-level `failed` (transaction, fulfillment, and shipment `failed` are
138
+ unchanged). The MCP `cancel-order` guidance no longer lists order-level `failed`
139
+ as a local cancel-from state.
140
+
141
+ - 3cbf9b6: Generated Payload types: `inventory-reservations` gains a `pending` (pre-payment
142
+ checkout hold) status alongside `held`/`released`/`consumed`, plus an optional
143
+ `expiresAt` TTL field. Additive and backward-compatible — part of the
144
+ checkout-time inventory reservation that prevents payment-window oversell (#1033).
145
+ - 1034772: Classify the new `inventory-adjustments` collection as SDK-internal and sync
146
+ generated Payload types. The collection is the Console-side append-only
147
+ finite-stock movement ledger (#1038); it is hidden from SDK/MCP collection
148
+ discovery.
149
+
150
+ Behavior note for direct `product-variants` updates: changing tracked `stock`
151
+ via the collection API now requires the write-only `stockAdjustmentReason`
152
+ field (`received | correction | damage | loss | cycle_count | other`) unless
153
+ the write comes from an instrumented server flow. Updates without it are
154
+ rejected with `400 stock_adjustment_reason_required`.
155
+
156
+ - 2313263: Align confirm-payment and public catalog contracts with server behavior.
157
+
158
+ The CLI `transaction confirm-payment` command now supports an explicit
159
+ `--idempotency-key`, rejects malformed amount tokens without truncation, and
160
+ accepts zero amounts per the confirm-payment contract. The SDK now exposes
161
+ `paymentKey` on confirm-payment params and stock-stripped catalog listing
162
+ response types.
163
+
164
+ - 188f052: Register the `order-export-profiles` collection in the SDK collection set
165
+ (server-only) and generate its Payload type. The collection stores reusable,
166
+ schema-validated order export layouts consumed by the Console export mapping
167
+ engine; it is not exposed on the public storefront/query surface.
168
+ - 9275bee: Clarify generated order display status field descriptions for the orders composite status UX.
169
+ - 2c98b63: `CreateOrderItem.product` and `.option` are now optional: the create-order
170
+ endpoint derives the line's product from the variant's parent server-side,
171
+ so storefront items may send `variant` + `quantity` only.
172
+ - 75f57f8: Order reads now include Shopify-style display axes in the generated SDK Payload
173
+ types: `displayFinancialStatus`, `displayFulfillmentStatus`, and non-null
174
+ `returnStatus`, while preserving the legacy compatibility status fields.
175
+ - 62a2966: Expose the generated `billing_key_update` billing-history type in the public SDK
176
+ Payload types.
177
+
178
+ ## 0.37.0
179
+
180
+ ### Minor Changes
181
+
182
+ - b6ce22b: Analytics: skip event sends on local hosts by default.
183
+
184
+ `createAnalytics()` and `<Analytics />` gain a `mode` option
185
+ (`'auto' | 'production' | 'development'`, default `'auto'`). In `'auto'` mode no
186
+ events are sent when the page runs on `localhost` / `127.0.0.1` / `*.local`;
187
+ validation and dev warnings still run and a one-time console notice is emitted.
188
+ Pass `mode: 'production'` to send while developing, or `mode: 'development'` to
189
+ force-disable on any host. The hosted analytics snippet gains an equivalent
190
+ `captureOnLocalhost` opt-in (`window.__01_analytics__.captureOnLocalhost` or
191
+ `data-capture-localhost="true"`). This is observable behavior INVARIANT 9.
192
+
193
+ - 3068b31: Add `createCommerceNotificationWebhookHandler` and related commerce notification webhook types on the public webhook subpath. `createCommerceEmailWebhookHandler` remains a compatibility alias. Update MCP webhook guidance shipped in the CLI MCP stdio artifact.
194
+ - 1b00174: BREAKING: Tighten product upsert swatch input types so color swatches require `color` and media swatches require `mediaItemId`.
195
+ - 5072a76: Add `PRODUCT_PLP_FIND_OPTIONS` for join-safe raw `products.find()` PLP queries and document `listingGroupsCatalog()` as the preferred listing path. MCP query-builder docs now explain Payload join-field default limits.
196
+ - 79e52c8: Add tenant-configurable initial order shipping refund policy on returns. SDK create-return and return-with-refund clients accept `initialShippingRefundAmount` and override note fields; CLI `return create` and `return refund` expose matching flags.
197
+ - 030e030: Improve SDK relation and order input ergonomics.
198
+
199
+ `resolveRelation<T>()` now accepts unknown relation values, and create-order
200
+ inputs accept `items` as a storefront-facing alias that serializes to the
201
+ existing `orderItems` endpoint field. The CLI order create path stays aligned
202
+ with the SDK order input contract.
203
+
204
+ - d661646: Add Shopify-like fulfillment preparation and shipment APIs. Fulfillment creation can start shipment without carrier/tracking, and fulfillment updates can add or correct tracking information later.
205
+
206
+ ### Patch Changes
207
+
208
+ - e6c6f59: Normalize community create/update helper responses that return Payload `{ doc }` wrappers so SDK callers receive the created or updated resource directly.
209
+ - bb22a83: Fix `IMAGE_SIZES` to match platform upload tiers `[200, 400, 800, 1200, 1600]` so `getImageUrl` and `getImageSrcSet` select real renditions instead of silently falling back to originals. Legacy numeric size keys (e.g. `1536`) remain supported at runtime.
210
+ - 02e41c8: Expose the operator-voided `Fulfillment.status = 'canceled'` value in generated SDK Payload types.
211
+ - ca495fc: Expose optional `ProductTag.color` metadata in generated SDK Payload types.
212
+
213
+ ## 0.36.0
214
+
215
+ ### Minor Changes
216
+
217
+ - c4956b2: Paid order cancel responses now include `refundPending: true` when a captured
218
+ payment still awaits storefront PG refund after local cancellation. Legacy
219
+ `reconciliationRequired` responses remain for older inline-PG-cancel rows.
220
+ MCP order-flow guidance reflects local-only cancel ownership.
221
+
222
+ **Consumer migration:** `providerRefunded` is no longer `true` on new cancels.
223
+ Paid local cancel responses now always have `refundedAmount: 0` and
224
+ `refundPending: true` instead of a positive `refundedAmount` and
225
+ `providerRefunded: true`.
226
+
227
+ - 06e061a: Add `POST /api/orders/resolve-cancel-refund` and
228
+ `client.commerce.orders.resolveCancelRefund(...)` so storefront/BFF code can
229
+ report PG cancel-refund success or failure back to the platform idempotently.
230
+ The existing `alreadyCanceled + refundPending` cancel-order response remains
231
+ backward-compatible and continues to accept any nonnegative `refundedAmount`;
232
+ new paid local-cancel responses still emit `refundedAmount: 0` while PG refund
233
+ settlement is pending by design (#826).
234
+ - b97d35e: BREAKING (0.x minor): Simplify listing projection — remove persisted listing
235
+ grouping and `listingPrimaryOption` across console, contracts, and SDK surfaces.
236
+ `ProductListingGroupsItem` drops `primaryOptionId`, `listingGroupingState`, and
237
+ `listingGroupingEmptyReason`; generated `Product` types drop `listingPrimaryOption`
238
+ and `listing.grouping*` fields; SDK no longer exports `ListingGroupingState` /
239
+ `ListingGroupingEmptyReason`. Swatch groups derive from the first product option
240
+ by `_order`. `buildProductListingCard` uses persisted min/max when both are present
241
+ and merges compare-at from groups when compare-at keys are absent. See
242
+ `packages/sdk/MIGRATION.md`.
243
+
244
+ ## 0.35.0
245
+
246
+ ### Minor Changes
247
+
248
+ - 10fff1d: Add the `@01.software/sdk/errors` public subpath for SDK error classes, type
249
+ guards, and factory helpers. The entrypoint re-exports the same surface already
250
+ available from the root package without pulling React, Next.js, or internal SDK
251
+ modules. ESM and CJS builds are included in the published artifact.
252
+
253
+ ## 0.34.0
254
+
255
+ ### Minor Changes
256
+
257
+ - BREAKING (0.x minor): Simplify listing projection — remove persisted listing
258
+ grouping and `listingPrimaryOption` across console, contracts, and SDK surfaces.
259
+ `ProductListingGroupsItem` drops `primaryOptionId`, `listingGroupingState`, and
260
+ `listingGroupingEmptyReason`; generated `Product` / `ProductsSelect` drop
261
+ `listingPrimaryOption` and `listing.grouping*` fields; SDK no longer exports
262
+ `ListingGroupingState` / `ListingGroupingEmptyReason`. Swatch groups derive from
263
+ the first product option by `_order` (migration reorders legacy primaries).
264
+ `buildProductListingCard` uses persisted min/max when both are present and
265
+ merges compare-at from groups when compare-at keys are absent.
266
+ See `MIGRATION.md` (Listing projection simplification).
267
+ - 0c12c2b: BREAKING (0.x minor): Remove the Canvas `BUILT_IN_NODE_TYPES` and
268
+ `BUILT_IN_EDGE_TYPES` exports. Canvas node and edge definitions now come from the
269
+ tenant database catalog. Optional starter rows are imported through explicit
270
+ migrate or seed commands; `useCanvasData()` defaults `nodeTypeDefs` and
271
+ `edgeTypeDefs` to empty arrays unless callers pass catalog data.
272
+ - bafcf2d: Add catalog/stock split commerce reads: `detailCatalog()`, `listingGroupsCatalog()`, `stockSnapshot()`, and `mergeProductDetailWithStock()` for edge-cached catalog shells with live inventory snapshots. Existing `detail()` and POST endpoints remain unchanged.
273
+ - 7990112: Product admin save splits Payload document writes from graph upsert; SDK mirrors upsert graph conflict and revision-required error bodies without depending on private contracts. CLI aligns with vitest 4 catalog for dependency health.
274
+ - 2bf6ddc: Add `ProductSelectionCodecOptions.fillDefaults` and exported `selectNext()` for product selection. Opt-in `fillDefaults` on `resolveProductSelection()` fills unselected options to a concrete variant using available-by-order rules aligned with listing `selectionHintVariant`. `selectNext()` applies slug-based option-click transitions, keeps compatible prior selections, and re-defaults incompatible ones. Default `fillDefaults` remains `false` for backward compatibility.
275
+ - a56c69a: Add optional `idempotencyKey` to retry-sensitive `server.commerce.orders`
276
+ mutations (`create`, `checkout`, `createFulfillment`, `createReturn`,
277
+ `returnWithRefund`, `confirmPayment`, `cancelOrder`). The SDK sends
278
+ `X-Idempotency-Key` and omits the key from JSON bodies. For `confirmPayment`,
279
+ `idempotencyKey` overrides `providerEventId` when both are set.
280
+
281
+ Expose the provider-verified `server.commerce.orders.cancelOrder()` method and
282
+ public cancel types. `CancelOrderResponse` is now a mutually exclusive union for
283
+ committed, `alreadyCanceled`, and `reconciliationRequired` outcomes, and the SDK
284
+ only sends the explicit cancel request body fields.
285
+
286
+ Add `orderCanceled` to the semantic commerce notification/webhook helper
287
+ surface. Operators should treat `alreadyCanceled` as idempotent success and
288
+ `reconciliationRequired` as the durable handoff signal after a provider refund
289
+ when local cancellation could not safely commit.
290
+
291
+ The matching private contracts package is ignored by changeset policy.
292
+
293
+ - fa4ce7d: Default `commerce.product.detail()` and `listingGroups()` to GET query transport for Edge CDN caching. Console POST endpoints remain supported for backward compatibility and large listing-groups batches.
294
+ - 09e9422: Default product selection URL stringify and `buildProductHref()` partial output to slug-compat params (`opt.color=ivory`) instead of canonical ID params. Adds `ProductListingGroup.optionSlug` in SDK and `@01.software/contracts` for listing href generation. Listing hint `variant=` links require `preferCompleteVariantFromHint: true`. Parse behavior unchanged. Opt out with `emit: 'canonical-id'`.
295
+
296
+ ## 0.33.0
297
+
298
+ ### Minor Changes
299
+
300
+ - 906577e: Add headless commerce email webhook helpers for routing commerce notification events, deriving idempotency keys, and typing tenant email configuration manifests.
301
+ - ecba235: BREAKING (0.x minor): Replace the product-detail `totalInventory` unlimited sentinel with explicit inventory rollups. `commerce.product.detail()` successful payloads now expose `product.hasUnlimitedVariant`; `product.totalInventory` is the tracked stock sum across non-unlimited variants and can be `null` when no variants are tracked.
302
+ - 156ff73: BREAKING (0.x minor): Change `commerce.product.detail()` to return a `ProductDetailResult`
303
+ discriminated union instead of `ProductDetail | null`. Successful responses now
304
+ return `{ found: true, product }`; product-detail 404 responses return
305
+ `{ found: false, reason }` with `not_found`, `not_published`, or
306
+ `feature_disabled`. Permission/auth responses, including 403 tenant mismatch,
307
+ continue to throw typed SDK errors. Any product-detail 404 without an
308
+ allowlisted code/reason also throws instead of being collapsed, so unexpected
309
+ backend absence states remain visible during integration.
310
+ - ef4abdf: Expose commerce notification webhook constants, public types, and a semantic event guard from the SDK webhook entrypoint.
311
+
312
+ ## 0.32.0
313
+
314
+ ### Minor Changes
315
+
316
+ - 4fea701: Add generic order payment confirmation support through `commerce.orders.confirmPayment()`.
317
+ Order creation item IDs now accept string or numeric entity identifiers while
318
+ legacy caller-supplied line prices remain compatibility-only inputs.
319
+ - 6407210: Add the server-only SDK tenant introspection API and route CLI schema and
320
+ feature-progress discovery through the SDK instead of command-local fetches.
321
+
322
+ ### Patch Changes
323
+
324
+ - 11c1878: Remove retired marker wording from order creation compatibility fields.
325
+ - bc94da6: Route customer auth requests through the shared SDK transport so request IDs,
326
+ usage-limit errors, API reason mapping, origin suggestions, and timeout/network
327
+ errors match the rest of the SDK while keeping customer auth endpoint retries
328
+ disabled. Customer auth failures now surface the same SDK-specific error classes
329
+ as other SDK requests instead of the previous generic API error shape.
330
+
331
+ ## Unreleased
332
+
333
+ ### Minor Changes
334
+
335
+ - BREAKING (0.x minor): `resolveProductSelectionMedia()` no longer returns
336
+ `product_primary` or `product_pool`; use `resolveProductDisplayMedia()` or
337
+ `resolveProductSelection()` display fallback when strict selection is `none`.
338
+ Option swatch selection returns the swatch image only, not the full product pool.
339
+ Listing primary display fallback is pool-only (`products.images[]`).
340
+
341
+ - Add `EventsClient` and `client.events` / `server.events` helpers for public
342
+ event occurrence range reads, event registration, guest registration lookup,
343
+ and guest self-cancel flows. These helpers require `X-Publishable-Key`, keep
344
+ `server.events` on the public event-helper credential boundary without
345
+ forwarding `secretKey`, and derive registration `customer` identity from
346
+ customer auth rather than public request body input. **Breaking:** **`POST
347
+ /api/event-registrations/register` rejects `body.customer` with `400
348
+ bad_request`;** bind customers with `Authorization: Bearer` only. See
349
+ `docs/events/public-api-contract.md` for migration. Guest-token lookup/cancel
350
+ helpers send tokens in POST bodies. Range helpers support calendar, category,
351
+ and tag filters aligned with the Console public range endpoint. Exported
352
+ structural `RootClient` / `RootServerClient` keep `events` optional for
353
+ object-literal mocks; `createClient()` / `createServerClient()` return
354
+ `RootClientWithEvents` / `RootServerClientWithEvents` with required `events`.
355
+
356
+ - **BREAKING (0.x minor):** Remove flat `swatchColor` from product-detail option
357
+ values, SDK matrix/selection shapes, and listing projections that mirrored the
358
+ removed Payload field. Use nested `swatch: { type, color, mediaItemId }` (or
359
+ selection `swatch.color` / `swatch.image`). `ProductApi.upsert()` and Console
360
+ HTTP upsert reject unknown `swatchColor` on option-value input; send
361
+ `swatch: { type: 'color', color: '#...' }` instead. MCP `product-upsert` no
362
+ longer documents `swatchColor` in the tool schema.
363
+
364
+ - Add handoff-aligned fields on `ProductSelectionAvailableValue`: `exists` (alias
365
+ of `available`), `label` (same source as `value`), and Shopify-shaped
366
+ `swatch: { color, image }` via exported `ProductSelectionAvailableSwatch`.
367
+ Flat `thumbnail` and `images` on selection values are unchanged. Document
368
+ selection-hint vs `fillDefaults` behavior in SDK README and `AGENTS.md`.
369
+
370
+ - Add `ProductSelectionCodecOptions.fillDefaults` and `selectNext()` for product
371
+ selection. Opt-in `fillDefaults` resolves partial selections to a concrete
372
+ variant using the same available-by-order rules as listing
373
+ `selectionHintVariant`. `selectNext()` applies option-click transitions while
374
+ keeping compatible prior values and re-defaulting incompatible ones.
375
+
376
+ - **BREAKING (0.x minor):** Align `CreateOrderItem` with the create-order API
377
+ request contract. `product`, `variant`, and `option` are required scalar IDs.
378
+ The create-order endpoint still accepts `unitPrice` and `totalPrice` as
379
+ optional compatibility inputs, but the server derives authoritative line money
380
+ values from product variants.
381
+
382
+ - **BREAKING (0.x minor):** Remove legacy product media fields from detail and
383
+ listing contracts. Selection media now resolves through
384
+ `resolveProductSelectionMedia` pointer/pool rules; direct
385
+ `variant.thumbnail`, option-value `thumbnail`/`images`, product `thumbnail`,
386
+ and `mediaSets` gallery fallback fields are no longer authoritative SDK
387
+ resolver inputs. Empty `mediaSets` intentionally falls through to selection
388
+ media. Deprecated one-release `resolveProductMedia` and
389
+ `resolveProductGallery` shims remain for migration, but legacy direct-media
390
+ fallback precedence is removed.
391
+
392
+ - Deprecate `resolveProductGallery`, `utils/product-gallery`, and related
393
+ `ProductMediaSetInput` / `ProductGallerySource` names as one-release shims
394
+ that forward or fall through to `resolveProductSelectionMedia`. Product detail
395
+ `mediaSets` and variant `gallerySource` fields are removed rather than
396
+ deprecated; only the gallery helper names remain as temporary shims.
397
+
398
+ ## 0.31.0
399
+
400
+ ### Minor Changes
401
+
402
+ - 6cadf1e: Remove the generated `parent` field from default tag collection types. Tags are
403
+ now flat by default across content, media, events, canvas, and ecommerce
404
+ taxonomy collections; category collections continue to expose `parent` for
405
+ hierarchy.
406
+ - 6cadf1e: Add `server.preview.detail()` for generic saved-record preview lookups and route
407
+ product `previewDetail()` through the generic preview detail endpoint.
408
+
409
+ Preview redirects now use `/api/preview/start?collection=<slug>&id=<id>` and
410
+ send tenant frontends to `<origin><draftPath>?token=...&collection=<slug>&id=...`.
411
+ Tenant preview configuration has moved to `tenants.previewDestinations` with
412
+ `draftPath` defaulting to `/api/01software/draft`; migrate old product-only
413
+ draft routes and `/api/products/*/preview` integrations to the generic
414
+ collection/id contract.
415
+
416
+ ## 0.30.1
417
+
418
+ ### Patch Changes
419
+
420
+ - auto release 5d91b13ba2
421
+
422
+ ## 0.30.0
423
+
424
+ ### Minor Changes
425
+
426
+ - 51a6399: **BREAKING (0.x minor):** Split feature-specific SDK surfaces out of the root entry so `createClient`
427
+ consumers do not need React Query, Next.js, Payload, rich text, canvas, or code
428
+ highlighting peers. The root entry is now the browser-safe core surface;
429
+ server-only code must import `createServerClient` from `@01.software/sdk/server`,
430
+ and React Query hooks/helpers must import from `@01.software/sdk/query`.
431
+
432
+ Migration notes:
433
+ - `createClient` remains available from `@01.software/sdk` and
434
+ `@01.software/sdk/client`.
435
+ - `createServerClient` must move to `@01.software/sdk/server`; it is no longer
436
+ exported from the root browser-safe entry.
437
+ - React Query hooks and cache helpers must move to `@01.software/sdk/query`.
438
+ - UI components live under explicit `@01.software/sdk/ui/*` sub-paths. Install
439
+ only the optional peers listed for the sub-paths you import.
440
+
441
+ - 51a6399: Add stable product-detail selection helpers for ecommerce storefronts.
442
+
443
+ Product detail responses now expose option and option-value compatibility slugs,
444
+ and the SDK adds helpers for building option matrices from detail responses,
445
+ parsing and stringifying selection URLs, and resolving selected/partial variant
446
+ state. New selection URLs use stable variant/option/value IDs; slug URLs remain
447
+ read-only compatibility input for older storefront links.
448
+
449
+ - 51a6399: Improve tenant-admin consumer ergonomics.
450
+
451
+ Server React Query helpers can now address server-only SDK collections such as
452
+ customer groups, reports, and community bans. SDK clients also accept an
453
+ explicit `apiUrl` override for staging, preview, self-hosted, and proxy
454
+ deployments. README examples now steer product catalog writes through the
455
+ transactional `server.commerce.product.upsert()` helper and clarify the current
456
+ local-only customer auth method boundary.
457
+
458
+ ### Patch Changes
459
+
460
+ - 51a6399: Strengthen packaged SDK boundary checks and document that Console-shared
461
+ contracts stay private.
462
+ - 51a6399: Fix product listing group detail links so grouped option-value selections emit
463
+ partial ID-based selection URLs before falling back to listing hint variants.
464
+
465
+ ## 0.29.0
466
+
467
+ ### Minor Changes
468
+
469
+ - 3061394: Add slug-based product detail selection helpers for ecommerce storefronts.
470
+
471
+ Product detail responses now expose option and option-value slugs, and the SDK
472
+ adds helpers for building option matrices from detail responses, parsing and
473
+ stringifying selection URLs, and resolving selected/partial variant state.
474
+
475
+ ## 0.28.0
476
+
477
+ ### Minor Changes
478
+
479
+ - 75b7b1c: Remove unused playlist and track fields from generated Payload types:
480
+ `playlists.coverArt`, `playlists.isCollaborative`, `playlists.videos`,
481
+ `tracks.content`, `tracks.isFeatured`, `tracks.publishedAt`, and
482
+ `tracks.isEmbeddable`.
483
+
484
+ ## 0.27.0
485
+
486
+ ### Minor Changes
487
+
488
+ - Relax generated collection types for title and event default fields that can
489
+ now be absent or null in tenant content responses.
490
+
491
+ - Add package repository metadata and align release scripts with the Changesets
492
+ and npm trusted publishing workflow.
package/MIGRATION.md ADDED
@@ -0,0 +1,183 @@
1
+ # @01.software/sdk Migration Notes
2
+
3
+ ## Shopify-shaped product listing fields (#1207)
4
+
5
+ Next minor release as a semver minor for the pre-1.0 SDK. This release removes
6
+ public product-detail exports and renames public union/sort literals, and must
7
+ be called out in release notes as `BREAKING (0.x minor)`.
8
+
9
+ ### Removed public exports
10
+
11
+ - `ProductDetailListing`
12
+ - `ProductDetailCatalogListing`
13
+ - `ProductListingGroupsCatalogListing`
14
+
15
+ ### Removed fields
16
+
17
+ `ProductDetail` and `ProductDetailCatalog` no longer include the `listing`
18
+ group. Replace each field as follows:
19
+
20
+ | Removed | New |
21
+ | ---------------------------------- | --------------------------------------------------------- |
22
+ | `listing.primaryImage` | `featuredImage` |
23
+ | `listing.minPrice` | `priceRange.minVariantPrice.amount` |
24
+ | `listing.maxPrice` | `priceRange.maxVariantPrice.amount` |
25
+ | `listing.isPriceRange` | `priceRange.isPriceRange` |
26
+ | `listing.minCompareAtPrice` | `compareAtPriceRange.minVariantPrice.amount` |
27
+ | `listing.maxCompareAtPrice` | `compareAtPriceRange.maxVariantPrice.amount` |
28
+ | `listing.availableForSale` | `availableForSale` |
29
+ | `listing.selectionHintVariant` | `selectedOrFirstAvailableVariant` |
30
+
31
+ The new range types are exported as `ProductPriceRange` (price range, with
32
+ `isPriceRange`) and `ProductMoneyRange` (compare-at range).
33
+
34
+ ### Renamed literals
35
+
36
+ - `ProductDetailDisplayMediaSource`: `'listing_primary'` → `'featured_image'`.
37
+ - `ProductListingPageSort`: `'listing.minPrice'` / `'-listing.minPrice'` /
38
+ `'listing.maxPrice'` / `'-listing.maxPrice'` →
39
+ `'priceRange.minVariantPrice.amount'` / `'-priceRange.minVariantPrice.amount'`.
40
+ - Private-contract helper `resolveListingPrimaryImagePointer` →
41
+ `resolveFeaturedImagePointer` (input field `listingPrimaryImage` →
42
+ `featuredImage`).
43
+
44
+ ### Product upsert response
45
+
46
+ `ProductApi.upsert()` (`POST /api/products/upsert`) renames its
47
+ projection-staleness hint:
48
+
49
+ ```diff
50
+ - { ok: true, product, listingProjectionStale: boolean }
51
+ + { ok: true, product, productProjectionStale: boolean }
52
+ ```
53
+
54
+ The CSV bulk-import per-row response renames `listingSyncOk` / `listingSyncError`
55
+ to `projectionSyncOk` / `projectionSyncError`.
56
+
57
+ ## Listing projection simplification
58
+
59
+ Target release: `0.34.0` as a semver minor for the pre-1.0 SDK. This release
60
+ contains breaking listing-groups and product upsert behavior and must be called
61
+ out in release notes as `BREAKING (0.x minor)`.
62
+
63
+ ### Removed fields
64
+
65
+ `ProductListingGroupsItem` no longer includes:
66
+
67
+ - `primaryOptionId`
68
+ - `listingGroupingState`
69
+ - `listingGroupingEmptyReason`
70
+
71
+ Generated `Product` / `ProductsSelect` types no longer include:
72
+
73
+ - top-level `listingPrimaryOption`
74
+ - `listing.groupingState`, `listing.groupingEmptyReason`, `listing.groupingCount`
75
+
76
+ Public SDK exports removed:
77
+
78
+ - `ListingGroupingState`
79
+ - `ListingGroupingEmptyReason`
80
+
81
+ Platform `ProductUpsertSchema` no longer accepts `listingPrimaryOption`
82
+ (released through the SDK; see SDK notes below).
83
+
84
+ Product upsert inputs no longer accept `listingPrimaryOption`.
85
+
86
+ ### Swatch grouping behavior
87
+
88
+ Listing-groups `groups` are now derived at read time from the **first product
89
+ option by `_order`**, not from a persisted primary option.
90
+
91
+ Migration `20260613_000000_drop_product_listing_grouping_and_primary_option`
92
+ **swaps option `_order` with the first option** when `listing_primary_option_id`
93
+ was set to a non-first option, so existing storefront swatch grouping is
94
+ preserved before the column is dropped. Option order in Admin may change for
95
+ affected products.
96
+
97
+ Before deploy, quantify products that configured a primary option (column exists
98
+ until that migration runs):
99
+
100
+ ```sql
101
+ SELECT COUNT(*) FROM products WHERE listing_primary_option_id IS NOT NULL;
102
+ ```
103
+
104
+ Products where the primary option was not already first (reordered by migration):
105
+
106
+ ```sql
107
+ WITH ranked AS (
108
+ SELECT
109
+ p.id AS product_id,
110
+ p.listing_primary_option_id,
111
+ po.id AS option_id,
112
+ ROW_NUMBER() OVER (
113
+ PARTITION BY p.id
114
+ ORDER BY
115
+ CASE
116
+ WHEN po._order ~ '^-?[0-9]+$' THEN po._order::numeric
117
+ ELSE 2147483647
118
+ END,
119
+ po._order NULLS LAST,
120
+ po.id
121
+ ) AS rn
122
+ FROM products p
123
+ JOIN product_options po ON po.product_id = p.id
124
+ WHERE p.listing_primary_option_id IS NOT NULL
125
+ )
126
+ SELECT COUNT(DISTINCT product_id)
127
+ FROM ranked
128
+ WHERE rn = 1 AND option_id <> listing_primary_option_id;
129
+ ```
130
+
131
+ ### `buildProductListingCard` price and availability
132
+
133
+ When **both** `product.priceRange.minVariantPrice.amount` and
134
+ `product.priceRange.maxVariantPrice.amount` are set, the SDK card uses those
135
+ persisted values instead of aggregating from `groups`. Compare-at fields are
136
+ taken from `product.compareAtPriceRange` only when both amount bounds are
137
+ present; otherwise compare-at is merged from `groups`, then on-the-fly
138
+ projection. Partial Product price ranges fall back to group aggregation
139
+ entirely.
140
+
141
+ When `product.availableForSale` is set, it takes precedence over group
142
+ availability. Ensure the Product projection stays in sync on product saves, or
143
+ cards may show stale prices relative to live variant data.
144
+
145
+ ## Canvas Tenant Catalog Runtime
146
+
147
+ Target release: `0.34.0` as a semver minor for the pre-1.0 SDK. This release
148
+ contains breaking Canvas API behavior and must be called out in release notes as
149
+ `BREAKING (0.x minor)`.
150
+
151
+ ### Removed Exports
152
+
153
+ The `@01.software/sdk/ui/canvas` entry no longer exports:
154
+
155
+ - `BUILT_IN_NODE_TYPES`
156
+ - `BUILT_IN_EDGE_TYPES`
157
+
158
+ The server barrel also no longer exports these `BUILT_IN_*` arrays.
159
+
160
+ The platform Canvas catalog concept has been removed. Canvas node and edge
161
+ types now live only in the tenant database catalog. Optional starter rows
162
+ (`text`, `image`, and `default`) are ordinary tenant data imported through the
163
+ explicit starter catalog migration or single-tenant seed command.
164
+
165
+ ### Runtime Catalog Inputs
166
+
167
+ `useCanvasData()` no longer merges SDK built-in node or edge definitions. Its
168
+ `nodeTypeDefs` and `edgeTypeDefs` options default to empty arrays.
169
+
170
+ Consumers must pass catalog definitions from one of these sources:
171
+
172
+ - `useCanvas()`, which returns `nodeTypeDefs` and `edgeTypeDefs` from the tenant
173
+ catalog API.
174
+ - Server props or loader data populated from `canvas-node-types` and
175
+ `canvas-edge-types`.
176
+
177
+ `CanvasRenderer` likewise expects `nodeTypeDefs` and `edgeTypeDefs` from the
178
+ tenant catalog when rendering dynamic nodes or styled edges. Image rendering is
179
+ field-based: image output comes from catalog fields with `fieldType: 'image'`,
180
+ not from a special `nodeTypeSlug === 'image'` branch. Do not rebuild the
181
+ removed `BUILT_IN_*` arrays in application code; seed the tenant catalog
182
+ instead. Server consumers should import CSS sanitizers from
183
+ `@01.software/sdk/ui/canvas/server`.