# SDK migrations

This file ships in both @lockerverse/sdk and @lockerverse/react. Use the copy in
the target installed release. This is an agent-run procedure, not an install
script. Installing a package does not edit host code or guarantee these steps ran.

## Upgrade procedure

1. Before installation, record the resolved installed version of each package
   from the lockfile or package manager, the host framework, and the features in
   use. Do not use a dependency range as proof of the installed version.
2. Select a published matching stable SDK/React pair. A copy-prompt version is a
   minimum, not a request to downgrade. Preserve a newer matching stable pair.
   Core-only consumers do not need to add React. Use the existing package manager
   and update the real lockfile. Follow peer requirements in the target manifests.
3. After installation, read this target file and SDK_RULES.md. React consumers
   must also read guides/integration.md and each applicable resource guide.
   Follow SDK_RULES.md to create or merge the short host-root AGENTS.md section
   so future upgrades use this procedure even without a new integration prompt.
4. For each affected package, apply all entries where old version < entry version
   <= target version, from oldest to newest. Include releases skipped by the
   upgrade. Use semantic version comparison, not string comparison. An Unreleased
   section is not a published migration and must not be applied to a stable host.
5. Apply required steps. Apply recommended steps when the feature and host support
   them and they fit the task. Keep deliberate host choices. For every skipped
   step, state why it does not apply or what prevents it. Do not silently count it
   as complete. Do not replace a framework, change payment mode, or publish a site
   merely because a migration recommends a capability.
6. Run the host's relevant existing build and checks. Inspect initial HTML when
   SSR applies and the browser behavior for the changed feature. Do not create
   live transactions. Report old/new versions, applied entries, automatic changes,
   skipped actions and reasons, check results, and any remaining work.

If the old version is unknown, identify it from the prior lockfile or Git history.
If it cannot be found, report that limit and use the baseline review below. Do not
claim that every historical migration was applied. Read this file even if the
version already matches: a previous upgrade may have missed host adoption steps.

## 0.2.196 — save reusable payment methods

- **Affected:** React one-time payments, subscriptions, auction Buy Now, and
  purchase recovery. Deferred Stripe Elements now requests `off_session` setup
  so its configuration matches the backend PaymentIntent and saves supported
  reusable methods, including Link, to the customer.
- **Required:** update the matching SDK/React packages and deploy the host with
  the backend payment-saving change. No host prop changes are required.
- **Unchanged:** existing purchases are not converted into reusable methods.
  Future charges can still require customer authentication. Methods without
  off-session support cannot be made reusable by this setting.
- **Check:** in Stripe test mode, complete supported payment methods and verify
  the successful PaymentIntent and customer payment-method attachment. Verify
  auction Buy Now and purchase recovery with the same backend configuration.

## 0.2.194 — sharper large auction gallery photos

- **Affected:** React auction item gallery responsive images.
- **Automatic:** the main gallery can select the existing 1920-pixel image
  variant for large displays and high-density screens. Smaller variants remain
  available; the browser selects a source for the rendered size and pixel ratio.
- **Required host changes:** upgrade Core and React together and deploy the host.
  No integration code changes are required.
- **Unchanged:** image layout, thumbnails, full-screen viewer, and checkout.
- **Check:** inspect the selected image source in a wide embedded gallery on a
  high-density screen. Confirm it can use the 1920-pixel variant without cropping.

## 0.2.193 — complete auction gallery photos

- **Affected:** React auction item galleries and photo thumbnails.
- **Automatic:** gallery photos fit inside their reserved space without cropping.
  Wide and tall photos remain complete, matching the full-screen photo viewer.
- **Required host changes:** upgrade Core and React together and deploy the host.
  No integration code changes are required.
- **Recommended:** use the original high-resolution product photo. This display
  change cannot restore detail missing from an uploaded source image.
- **Unchanged:** catalog cards, gallery dimensions, navigation, and checkout.
- **Check:** inspect a wide and a tall photo on desktop and mobile. Confirm all
  edges remain visible in the item gallery, thumbnails, and full-screen viewer.

## 0.2.191 — auction item additional charges

- **Affected:** Core auction item data, purchase quotes, and React auction checkout.
- **Automatic:** optional `additionalCharge` charges the first-item amount plus the
  additional-item amount for each further unit. Checkout and receipts show the configured charge
  separately. Bids use one unit and add the first-unit charge only if the bid wins.
  The bid amount and minimum increments remain unchanged. `maxQuantityPerOrder` limits each order; null inventory remains unlimited.
- **Required:** deploy the matching auction backend before enabling additional charges.
  Upgrade Core and React together. Custom purchase forms must obtain `getPurchaseQuote`,
  display the charge, and submit `expectedAdditionalChargeCents` with `expectedTotalCents`.
  Custom bid forms must disclose the first-unit charge and submit the same expected
  charge and total fields. Winner settlement uses the charge saved with the bid.
  Service fees continue to use merchandise subtotal only. Existing items need no edits.
- **Optional:** set `--lockerverse-auction-catalog-columns` on the auction style to
  choose desktop grid columns. Mobile retains one column.
- **Check:** compare one, two, and maximum quantity totals with the server quote,
  verify the per-order limit, and inspect the named charge row before payment.

## 0.2.189 — widget load recovery and Sentry releases

- **Affected:** Core widget loading and SDK failure reporting.
- **Automatic:** a widget GET retries once after a network failure or request
  timeout, with a full timeout for each attempt. Invalid responses, cancellation,
  HTTP errors, and payment submissions do not retry. Only the final failure is
  reported. Errors expose the safe optional `failureKind` field; Sentry receives
  `sdk.failure_kind` and a valid `lockerverse-sdk@<version>` release name.
- **Required host changes:** upgrade Core and React together and deploy the host.
  No integration code changes are required.
- **Check:** interrupt the first widget request and confirm that the second loads
  the widget. Check the final failure classification and Sentry release association.

## 0.2.185 — shipping for additional items

- **Affected:** Core checkout estimates and the React donation launcher.
- **Automatic:** `requiredShipping.additionalUnitAmountCents` adds a shipping
  charge for each trigger item after the first. The shipping product remains one
  line with quantity one. Omitted or zero values retain the flat shipping charge.
- **Required host changes:** upgrade Core and React together. Custom price
  summaries must include the additional charge and render authoritative quotes.
  The backend must support the field before a widget enables it.
- **Unchanged:** product prices, email eligibility, fixed discounts, donation-only
  orders, and widgets without this optional setting.
- **Check:** select one, two, and the maximum allowed trigger quantity. Confirm the
  local summary and server quote agree; removing all trigger items removes shipping.

## 0.2.184 — single focus boundary for form fields

- **Affected:** React form controls and the shared phone field in payment and signup.
- **Automatic:** the focus outline overlaps the field border, so focus has one
  clear boundary instead of two separated rings. Keyboard focus remains visible;
  the phone country selector keeps its own inset focus indicator.
- **Required host changes:** none; upgrade Core and React together.
- **Check:** focus the email and phone fields with a pointer and keyboard. Each
  field must have one continuous focus boundary without a gap.

## 0.2.183 — email discounts and required shipping

Required: upgrade Core and React together. Existing email percentage discounts need no host changes.

Widgets can now use a private contact list for email eligibility, a fixed amount discount, and an optional discount message. Entered-email matching remains unchanged. Public quotes contain optional `amountOffCents` and `message`; custom renderers must not assume `percentageOff` exists.

Required shipping appears in `catalog.widget.requiredShipping`. Do not offer this product as a separate shopper choice. The SDK adds its quantity once when a trigger product is selected; the server also enforces this rule. Render authoritative quote line items and totals, including shipping. The built-in launcher and payment summary handle this automatically.


## 0.2.177 — Secure checkout loading recovery

- **Affected:** React payment widget Stripe fields.
- **Automatic:** failed field or script loads show a reload action. Fields that
  remain unready for 30 seconds show a delay message. Late readiness removes
  the message without resetting the checkout or submitting a payment.
- **Required host changes:** none; keep Core and React versions matched.
- **Check:** block Stripe loading in an isolated browser, confirm the message,
  restore access, and use Reload checkout. Confirm normal fields still load.
- Reload is an explicit customer action and can clear unsaved form entries.
  Saved payment recovery remains in session storage.


## 0.2.175 — Match Stripe Elements payment method configuration

- **Affected:** Core checkout submission and React payment widgets.
- **Automatic:** React configures explicit card, Link, and community-enabled bank
  methods in Stripe Elements and marks the confirmation request with
  `paymentMethodConfiguration: "explicit"`. This matches the backend's Stripe
  PaymentIntent configuration.
- **Required:** deploy the backend that supports this optional marker before
  upgrading React. Keep Core and React matched. Existing Core-only callers omit
  the marker and retain automatic payment methods. Custom Elements integrations
  must send the marker only when they use the explicit method list.
- **Check:** submit card and bank payments through Stripe Elements in test mode,
  including recurring checkout. Confirm pending recovery and settlement.

## 0.2.173 — widget ACH and SDK checkout UI

### Bank authorization terms

- **Affected:** React payment widgets with ACH enabled.
- **Automatic:** Stripe displays its bank authorization terms before payment confirmation.
- **Adoption:** update the matching SDK/React pair. No prop changes are required.
- **Check:** confirm that the bank authorization text is visible when a bank account is selected.

### Widget ACH and subscription payment recovery

- **Affected:** Core checkout data and React payment widgets.
- **Automatic:** bank payment availability follows the stored community setting
  returned by the backend. Missing policy remains disabled.
  Pending payments keep their existing payment reference. A failed subscription
  invoice can return `action_required` with `requiresAction: false` and `retryUrl`;
  React shows a link to pay the same invoice instead of creating a second subscription.
  Bank microdeposit verification uses the same recovery link for Stripe's hosted
  verification page.
- **Required for custom payment UI:** preserve the reference for pending and
  action-required results. Handle `retryUrl` by opening the provider recovery page, and recover
  status before permitting a new checkout. Do not treat submission as settlement.
- **Adoption:** deploy the matching backend policy and recovery contract before
  enabling ACH. Existing React hosts need no component prop changes. Keep Core and
  React versions matched when upgrading. Auction payment methods are unchanged.
- **Check:** verify disabled/enabled bank visibility and pending, bank
  verification, invoice retry, success, and terminal failure in Stripe test mode.
  Do not create a live transaction for this check.

### Check pending payment status

- **Affected:** React payment widgets with unresolved payments.
- **Automatic behavior:** the existing pending-payment screen now offers Check
  payment status. It checks the saved payment reference and cannot submit a new
  payment. The control is disabled while the check runs.
- **Required host changes:** none. Update Core and React together.
- **Verification:** complete a test bank payment, return to its pending checkout,
  and check its status. Confirm completion clears recovery storage.

### SDK payment recovery and completion UI

- **Affected:** React payment widgets and custom hosts that persist payment recovery.
- **Optional adoption:** pass `recoveryStorageKey` to `LockerversePayment` to let
  the SDK save and restore the pending payment in session storage. Use a stable
  key scoped to the API environment, community, and widget. Remove the host's
  storage code and recovery-driven component key. Do not combine automatic
  persistence with a second host persistence writer.
- **Compatibility:** the SDK reads the hosted Next app's existing version 1
  records when the same key is used. It writes version 2 records with widget
  identity. It checks widget and selection identity before recovery and keeps
  an unresolved record if those details differ. Recovery uses the saved connected
  account even if current payment routing has changed. Storage is read after hydration,
  before the payable form mounts. No contact details or payment tokens are saved.
- **Optional UI adoption:** use `completionView="summary"` for the SDK confirmation
  panel and remove the host's duplicate success panel. Completion callbacks still
  run. The default inline message and explicit `resumePayment` integrations remain
  supported. Auctions and legacy custom checkout forms are unchanged.
- **Check:** reload a pending checkout and confirm the existing payment is checked;
  verify a changed selection cannot discard it. Check both paid and free order
  confirmation panels. Do not submit a live transaction for this check.

## 0.2.170 — six-month payment widgets

Affected: @lockerverse/sdk checkout and @lockerverse/react payment widgets.

- **Required:** upgrade both packages together before offering Products whose
  `paymentOption` is `every-six-months`. This option requires a backend that
  supports a Stripe month interval with an interval count of 6.
- **Automatic:** catalog validation, recurring selection, Stripe subscription
  mode, checkout summaries, and payment buttons recognize the new option.
- **Recommended:** custom host price labels should show “Every 6 months”. Fixed
  hosted product URLs must omit `amount` and `paymentOption` overrides.
- **Unchanged:** one-time, monthly, and annual Products retain their behavior.
- **Check:** load a six-month Product and confirm its amount and cadence before
  submission. Do not submit a live payment for an integration check.


## 0.2.166 — single dropdown arrow

- **Affected:** native single-select custom fields in React signup and payment forms.
- **Automatic:** removes the conflicting browser arrow so the existing SDK arrow
  appears once. Field options, values, and selection behavior are unchanged.
- **Adoption:** update the matching SDK/React packages and deploy the host to apply
  the corrected stylesheet. No host code or saved field changes are required.
- **Check:** confirm that the dropdown shows one arrow and options remain selectable.

## 0.2.165 — multi-select custom fields

- **Affected:** React signup and payment forms with `multi_select` custom fields.
  The field now opens a dropdown with multiple choices instead of a native listbox.
  Accessible dropdown support adds Base UI Select to the signup bundle. The packed
  signup consumer measures 111.80 kB brotli, about 32 kB above its former 80 kB
  budget; hosts should account for this increase in initial JavaScript.
- **Required:** upgrade the matching SDK/React packages and deploy the host with
  its existing signup or payment stylesheet. No host code or saved field changes
  are required. Selected option IDs remain arrays; single-select fields are unchanged.
- **Check:** open the dropdown, select and remove multiple options, and confirm
  keyboard navigation, Escape, and required-field feedback. Do not submit a live
  signup or payment for this check.

## Existing integration baseline through 0.2.161

This guide starts with the current integration baseline. It is not a complete
record of older breaking changes. For an integration created before this guide,
review this section once, including when its version already matches the target.
The feature guide and public types in the target package define the exact API.

### Required when applicable

- **Hosts that use both React and Core:** keep installed versions matched and use public entry points.
  Read the installed contract instead of an old copied integration prompt.
- **Auction media proxy:** if using mediaBaseUrl, pass the full loaded auction
  snapshot to components and initialAuction. Forward w and f query parameters
  unchanged. Check that a resized response has the expected dimensions and type.
- **Public route identity:** keep configured community and auction identity fixed.
  Use real item and return links. Handle missing items without selecting another
  item silently. Follow the host router's missing-page behavior.
- **Checkout and recovery:** preserve supported recovery state and private data
  handling. Never restart an uncertain transaction to recover from a load error.

### Recommended host adoption

- **Existing SSR hosts:** load public data on the server and seed
  useLockerverseAuction with initialAuction or useLockerverseAuctions with
  initialAuctions. Keep public content outside client-only payment boundaries.
  Keep that content visible during silent refresh. Verify it in the raw response.
- **Dedicated auction item pages:** set itemHeadingLevel={1}; avoid a competing
  page title heading. Embedded item views can keep the default level 2.
- **Gallery:** set galleryImageSizes when the host differs from the default
  full-width mobile / 45vw desktop layout. Check the first image before hydration
  and selected photos after interaction. Keep full-screen sizing separate.
- **Import boundaries:** use feature entry points such as
  @lockerverse/react/auction-item and @lockerverse/react/auction-data. Remove host
  imports that eagerly load payment UI when the page does not yet need it.
- **Host metadata and assets:** check offer descriptions against current prices.
  Keep local fonts, responsive photos, and background videos within the host's
  performance budget. These are host tasks, not automatic SDK transformations.

### Automatic SDK behavior in the baseline

Supported auction media paths use responsive sizes through the configured proxy.
The gallery gives the first photo high priority and uses eager/lazy loading for
selected/other photos. Transaction headings follow the item heading level.
Auction checkout code is deferred until payment or recovery needs it. These
benefits require the supported components and data paths; custom host UI must
adopt the corresponding APIs itself. The SDK cannot remove the host's own eager
imports or server-render a browser-only website.

## Versioned changes

### 0.2.161 — Deferred auction checkout code

Affected: @lockerverse/react auction item and transaction UI.

- **Automatic:** the supported auction UI loads checkout code when payment or
  recovery needs it. No public prop change is required.
- **Recommended:** use the narrow auction imports and remove unused eager payment
  imports from the host. Do not remove payment peers required by the chosen flow.
- **Check:** compare initial page requests with checkout requests. Public item
  content must remain available before checkout loads; recovery must keep its
  existing state. Do not expect the total size of every reachable chunk to shrink.

### 0.2.160 — Transaction heading hierarchy

Affected: @lockerverse/react auction item UI.

- **Automatic:** transaction and status headings follow the item heading level.
- **Recommended:** dedicated pages should use itemHeadingLevel={1}. Embedded
  views should retain the level that fits their surrounding page.
- **Check:** inspect the rendered heading order, including transaction states.
  This change must not require a new host CSS workaround or a widget remount.

### 0.2.159 — Gallery loading and item heading controls

Affected: @lockerverse/react auction item UI.

- **Automatic:** selected photos load eagerly and other photos load lazily. The
  first photo has high fetch priority; lazy photos can use automatic image sizing.
- **Recommended:** set galleryImageSizes for a custom host container and use
  itemHeadingLevel={1} on a dedicated item page. Read guides/auctions.md for the
  supported props. Embedded views can keep the defaults.
- **Check:** inspect the first response, image request sizes, and heading order.
  Check gallery selection and full-screen viewing without changing image quality.

### 0.2.158 — Responsive images through a configured proxy

Affected: @lockerverse/react auction images and @lockerverse/sdk auction data.

- **Automatic:** supported auction images retain responsive resize URLs through
  the configured mediaBaseUrl instead of losing resizing on that proxy path.
- **Required when using a proxy:** pass the full loaded snapshot to the UI and
  server seed. Configure the host rewrite to forward w and f unchanged to the
  media service. Do not reconstruct the snapshot and discard mediaBaseUrl.
- **Check:** confirm resized response dimensions and content type through the
  actual proxy. Signed, external, and unsupported URLs must keep their original
  behavior. Hosts without a custom proxy do not need a proxy configuration change.

## Entry format for future releases

Add new version entries above older entries. Before publication, replace any
Unreleased heading with the actual release version. Keep prior entries intact.
Each entry must state:

- Version and affected packages/features.
- Required changes, with the old and new API or behavior for breaking changes.
- Recommended host changes and the conditions where they apply.
- Automatic improvements and cases that need no host edit.
- Completion checks and any limits or manual follow-up.

For a new installation, use the current feature guides and baseline instead of
reproducing old APIs from migration examples.
