@doswiftly/storefront-operations 15.1.0 → 16.0.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/AGENTS.md +26 -3
- package/CHANGELOG.md +239 -0
- package/README.md +3 -1
- package/fragments.graphql +31 -1
- package/llms-full.txt +62 -3
- package/operations.json +27 -4
- package/package.json +1 -1
- package/queries.graphql +7 -0
- package/schema.graphql +21 -0
package/AGENTS.md
CHANGED
|
@@ -27,10 +27,10 @@ consumer's `codegen.ts` references this package's `.graphql` files as
|
|
|
27
27
|
live in the consumer's repo.
|
|
28
28
|
|
|
29
29
|
<!-- AUTOGEN:STATS:BEGIN — auto-regenerated, do not edit by hand -->
|
|
30
|
-
- **Schema version**:
|
|
31
|
-
- **Queries**:
|
|
30
|
+
- **Schema version**: 16.0.0
|
|
31
|
+
- **Queries**: 52
|
|
32
32
|
- **Mutations**: 40
|
|
33
|
-
- **Fragments**:
|
|
33
|
+
- **Fragments**: 102
|
|
34
34
|
<!-- AUTOGEN:STATS:END -->
|
|
35
35
|
|
|
36
36
|
## Loading order
|
|
@@ -174,6 +174,29 @@ semantics). Idempotency is the caller's responsibility. If you need retries
|
|
|
174
174
|
on a mutation, wrap with your own backoff logic and check `userErrors` to
|
|
175
175
|
decide whether to retry.
|
|
176
176
|
|
|
177
|
+
### Configuration sources — `doswiftly.config.ts` first, env vars only as fallback
|
|
178
|
+
|
|
179
|
+
`@doswiftly/storefront-sdk` takes `apiUrl` and `shopSlug` as **explicit
|
|
180
|
+
`config`** on `createStorefrontClient` / `<StorefrontProvider>`. The SDK does
|
|
181
|
+
not read env vars, sniff hostnames, or inspect request headers — the
|
|
182
|
+
storefront supplies the values.
|
|
183
|
+
|
|
184
|
+
Scaffolded storefronts (`doswiftly init`) ship a config helper
|
|
185
|
+
(`lib/graphql/config.ts`) that walks three sources in order:
|
|
186
|
+
|
|
187
|
+
1. **`doswiftly.config.ts`** — preferred. Committed config file generated at
|
|
188
|
+
scaffolding. No env wiring needed in normal use.
|
|
189
|
+
2. **`NEXT_PUBLIC_API_URL` + `NEXT_PUBLIC_SHOP_SLUG`** — fallback for local
|
|
190
|
+
dev or storefronts scaffolded outside `doswiftly init`. `doswiftly dev`
|
|
191
|
+
rewrites `NEXT_PUBLIC_API_URL` at runtime to point at a local CORS proxy.
|
|
192
|
+
3. **`http://localhost:8000` + `demo-shop`** — last-resort defaults.
|
|
193
|
+
|
|
194
|
+
If you generate code that falls back to env vars, use **exactly these names**.
|
|
195
|
+
**Do NOT invent alternatives** like `API_URL`, `STOREFRONT_URL`,
|
|
196
|
+
`TENANT_SLUG` — `doswiftly dev` keys off the canonical names; alternatives
|
|
197
|
+
mean the proxy starts but the storefront still calls the production API
|
|
198
|
+
directly, and CORS errors only surface on the first client-side mutation.
|
|
199
|
+
|
|
177
200
|
## When in doubt
|
|
178
201
|
|
|
179
202
|
- **Schema question** ("what fields are on `X`?") → grep `schema.graphql`
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,244 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 16.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- ca67b92: **BREAKING** — the formatting utilities switch from a hardcoded 13-currency map to runtime-driven `Intl.NumberFormat` resolution. Every ISO 4217 currency known to the runtime is now supported, with the locale-correct symbol and separators.
|
|
8
|
+
|
|
9
|
+
**API changes**
|
|
10
|
+
- `formatDate(date, locale)` — `locale` is now a required argument. The previous hardcoded `'en-US'` default is gone.
|
|
11
|
+
- `formatDateTime(date, locale)` — `locale` required.
|
|
12
|
+
- `formatNumber(num, locale)` — `locale` required.
|
|
13
|
+
- `formatPrice(price, locale?)` — `locale` is now optional. When omitted, the runtime default (`Intl.NumberFormat().resolvedOptions().locale`) is used. The previous `CURRENCY_LOCALES`-keyed auto-selection is gone.
|
|
14
|
+
- `formatAmount(amount, currencyCode, locale?)` — third argument added (optional).
|
|
15
|
+
- `formatPriceRange(min, max, locale?)` — third argument added (optional).
|
|
16
|
+
- `getCurrencySymbol(code, locale?)` — second argument added (optional). The symbol is derived from `Intl.NumberFormat.formatToParts()`; output depends on the locale (`getCurrencySymbol('PLN', 'pl-PL') === 'zł'`, `getCurrencySymbol('PLN', 'en-US') === 'PLN'`).
|
|
17
|
+
|
|
18
|
+
**Removed exports**
|
|
19
|
+
- `CURRENCY_SYMBOLS` — the 13-entry map is gone. Use `getCurrencySymbol(code, locale)` instead, or read the symbol from `Intl.NumberFormat.formatToParts()` directly.
|
|
20
|
+
- `CURRENCY_LOCALES` — the locale-to-currency map is gone. Pick the locale from the storefront's i18n context (or read `shop.localeToCurrencyMap` from the API for per-shop overrides) and pass it to `formatPrice` / `formatAmount`.
|
|
21
|
+
|
|
22
|
+
**Why**
|
|
23
|
+
- The hardcoded 13-currency map covered ~7% of the ISO 4217 currencies the API now ships in `CurrencyCode` (~180 entries). Every currency outside that list silently fell back to `en-US` formatting — a Brazilian (BRL) or Indian (INR) storefront had to either write its own formatter or accept US-style output.
|
|
24
|
+
- Locale↔currency is a **per-shop** decision (`shop.localeToCurrencyMap` in the schema is explicitly marked SSOT). A globally-hardcoded map in the SDK is the wrong place for that knowledge — it makes Polish customers of a multi-locale shop unable to see PLN in `'en-PL'` even when the merchant configured it.
|
|
25
|
+
- Money precision: `formatPrice` and `formatAmount` no longer apply `parseFloat` to `Money.amount`. Decimal strings are forwarded to `Intl.NumberFormat.format()` verbatim, preserving precision across locales and unusual subunit currencies (JPY/KRW zero-decimal, BHD/JOD/KWD three-decimal, ISK rounding).
|
|
26
|
+
|
|
27
|
+
**Migration**
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// Before
|
|
31
|
+
import {
|
|
32
|
+
formatDate,
|
|
33
|
+
formatPrice,
|
|
34
|
+
CURRENCY_LOCALES,
|
|
35
|
+
CURRENCY_SYMBOLS,
|
|
36
|
+
} from "@doswiftly/storefront-sdk";
|
|
37
|
+
|
|
38
|
+
formatDate(order.createdAt); // hardcoded "Dec 9, 2025"
|
|
39
|
+
formatPrice({ amount: "12.50", currencyCode: "PLN" }); // auto-picked pl-PL → "12,50 zł"
|
|
40
|
+
CURRENCY_LOCALES.PLN; // "pl-PL"
|
|
41
|
+
CURRENCY_SYMBOLS.PLN; // "zł"
|
|
42
|
+
|
|
43
|
+
// After (Client Components)
|
|
44
|
+
import { useLocale } from "next-intl";
|
|
45
|
+
import {
|
|
46
|
+
formatDate,
|
|
47
|
+
formatPrice,
|
|
48
|
+
getCurrencySymbol,
|
|
49
|
+
} from "@doswiftly/storefront-sdk";
|
|
50
|
+
|
|
51
|
+
const locale = useLocale(); // e.g. "pl-PL"
|
|
52
|
+
formatDate(order.createdAt, locale);
|
|
53
|
+
formatPrice({ amount: "12.50", currencyCode: "PLN" }, locale);
|
|
54
|
+
getCurrencySymbol("PLN", locale); // "zł"
|
|
55
|
+
|
|
56
|
+
// After (Server Components / Route Handlers)
|
|
57
|
+
import { getLocale } from "next-intl/server";
|
|
58
|
+
const locale = await getLocale();
|
|
59
|
+
formatDate(order.createdAt, locale);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For per-shop locale↔currency overrides, read `shop.localeToCurrencyMap` from the Storefront API and resolve the locale yourself before calling `formatPrice` / `formatAmount`.
|
|
63
|
+
|
|
64
|
+
**New: Context-driven format hooks**
|
|
65
|
+
|
|
66
|
+
`@doswiftly/storefront-sdk/react` now ships convenience hooks that pull the active language from `useLanguageStore` (inside `<StorefrontProvider>`) and return a memoised, locale-bound formatter. Use them when you don't want to pass `locale` to every call:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import {
|
|
70
|
+
useFormatPrice,
|
|
71
|
+
useFormatAmount,
|
|
72
|
+
useFormatPriceRange,
|
|
73
|
+
useFormatDate,
|
|
74
|
+
useFormatDateTime,
|
|
75
|
+
useFormatNumber,
|
|
76
|
+
useGetCurrencySymbol,
|
|
77
|
+
} from '@doswiftly/storefront-sdk/react';
|
|
78
|
+
|
|
79
|
+
function Cart() {
|
|
80
|
+
const formatPrice = useFormatPrice();
|
|
81
|
+
return <span>{formatPrice(item.price)}</span>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function OrderRow() {
|
|
85
|
+
const formatDate = useFormatDate();
|
|
86
|
+
return <span>{formatDate(order.processedAt)}</span>;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Each hook accepts an optional last `localeOverride` argument that wins over the store value — useful for a "show in US format" toggle on a single element:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const formatPrice = useFormatPrice();
|
|
94
|
+
return <span>{formatPrice(item.price, 'en-US')}</span>;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Resolution per call: `localeOverride` → `useLanguageStore().language` → runtime default.
|
|
98
|
+
|
|
99
|
+
Use the vanilla `formatPrice` / `formatDate` / etc. from `@doswiftly/storefront-sdk` (no hook) with an explicit `locale` for server components, e-mail templates, or any code path outside a provider.
|
|
100
|
+
|
|
101
|
+
`formatPercentage` is unchanged.
|
|
102
|
+
|
|
103
|
+
`@doswiftly/storefront-operations` bumped to keep linked parity — no operations changes.
|
|
104
|
+
|
|
105
|
+
### Minor Changes
|
|
106
|
+
|
|
107
|
+
- 885c011: Re-export checkout types from the public API. `CartClient` methods added in 15.1.0 (`getAvailablePaymentMethods`, `getAvailableShippingMethods`) returned typed payloads, but the named types were not part of the public surface — component props and function signatures touching these payloads required `Awaited<ReturnType<...>>` workarounds. This change closes that gap.
|
|
108
|
+
|
|
109
|
+
**Newly exported types:**
|
|
110
|
+
- `PaymentMethod`, `AvailablePaymentMethods` — shape returned by `CartClient.getAvailablePaymentMethods()`
|
|
111
|
+
- `AvailableShippingMethod`, `AvailableShippingMethodsPayload`, `FreeShippingProgress`, `DeliveryEstimate`, `ShippingCarrier`, `DeliveryType` — shape returned by `CartClient.getAvailableShippingMethods()`
|
|
112
|
+
- `PickupPoint`, `PickupPointInput` — locker / pickup-point delivery (surfaced via `MailingAddress.pickupPoint` and `CartAddressInput.pickupPoint`)
|
|
113
|
+
- `CartAttributeInput` — input shape for `CartClient.updateAttributes()`
|
|
114
|
+
- `ShippingAddressInput` — input shape for the `availableShippingMethods` standalone query
|
|
115
|
+
|
|
116
|
+
**Example:**
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import type {
|
|
120
|
+
AvailableShippingMethodsPayload,
|
|
121
|
+
AvailableShippingMethod,
|
|
122
|
+
DeliveryType,
|
|
123
|
+
} from "@doswiftly/storefront-sdk";
|
|
124
|
+
|
|
125
|
+
function isPickup(method: AvailableShippingMethod): boolean {
|
|
126
|
+
return method.deliveryType === "PICKUP_POINT";
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
No runtime changes — types already existed internally; this change only adds them to the published surface.
|
|
131
|
+
|
|
132
|
+
`@doswiftly/storefront-operations` bumped to keep linked parity — no operations changes.
|
|
133
|
+
|
|
134
|
+
- fd3d199: Expose `cart.cost.totalDiscount` and `cart.cost.totalShipping` through the `CartCost` fragment.
|
|
135
|
+
|
|
136
|
+
The schema already exposed `CartCost.totalDiscount: Money!` (aggregate of every entry in `cart.discountAllocations`) and `CartCost.totalShipping: Money` (cost of the currently selected shipping method, `null` until one is selected), but the shared `CartCost` fragment did not select them — so they were not part of the typed `Cart.cost` returned by `CartClient`. Storefronts wanting to render a single "Discounts: -X" row or a shipping summary had to either sum `discountAllocations` client-side (precision-sensitive across currencies) or query the schema directly and bypass the typed surface.
|
|
137
|
+
|
|
138
|
+
After this release, both fields are part of `Cart.cost` returned by every `CartClient` operation — `get`, `create`, `addItems`, `updateItems`, `removeItems`, `setShippingAddress`, `setBillingAddress`, `selectShippingMethod`, `selectPaymentMethod`, `updateBuyerIdentity`, `updateDiscountCodes`, `updateNote`, `updateAttributes`, `applyGiftCard`, `removeGiftCard`, `updateGiftCardRecipient`.
|
|
139
|
+
|
|
140
|
+
**Example:**
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const cart = await cartClient.get(cartId);
|
|
144
|
+
|
|
145
|
+
const summary = {
|
|
146
|
+
subtotal: cart.cost.subtotal,
|
|
147
|
+
discount: cart.cost.totalDiscount, // Money — defaults to amount 0
|
|
148
|
+
shipping: cart.cost.totalShipping, // Money | null — null until selectShippingMethod()
|
|
149
|
+
tax: cart.cost.totalTax,
|
|
150
|
+
total: cart.cost.total, // grand total — use directly on checkout summary
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`totalDiscount` is required (defaults to amount 0 when no discount applies). `totalShipping` is nullable — `null` means no shipping method has been selected yet, an amount of 0 means a free-shipping method was selected.
|
|
155
|
+
|
|
156
|
+
Additive — existing consumers keep every field they had before, no breaking change.
|
|
157
|
+
|
|
158
|
+
`@doswiftly/storefront-operations` bumped to keep linked parity (fragment update).
|
|
159
|
+
|
|
160
|
+
- 51091df: Expose `Cart.status` and `Cart.completedOrder` so storefronts can detect a completed (or expired / abandoned) cart on read, without having to attempt a mutation first and react to its `userErrors[].code`.
|
|
161
|
+
|
|
162
|
+
**New fields**
|
|
163
|
+
- `Cart.status: CartStatus!` — lifecycle status (`ACTIVE`, `ABANDONED`, `CONVERTED`, `RECOVERED`, `EXPIRED`). Only `ACTIVE` carts accept mutations; any other status rejects subsequent mutations with `CartErrorCode.ALREADY_COMPLETED`.
|
|
164
|
+
- `Cart.completedOrder: Order` — the order this cart converted into. Populated only when `status === CONVERTED`; null on every other status.
|
|
165
|
+
|
|
166
|
+
**Why**
|
|
167
|
+
|
|
168
|
+
When a buyer returned to the checkout page after completing their order (SSR re-render, deep link, "back" button after redirect), the SDK could only ask `cart(id)` for the cart and got the full pre-completion state back — every form value still there, the "Pay" button still active. The first mutation then failed with `ALREADY_COMPLETED`, after the buyer had already filled out fields. With `status` exposed, the storefront detects the terminal state on initial render and redirects to the order confirmation directly — using the `accessToken` on `completedOrder` for guest tracking, no extra `orderByToken` round-trip.
|
|
169
|
+
|
|
170
|
+
**Example**
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
const cart = await cartClient.get(cartId);
|
|
174
|
+
if (!cart) {
|
|
175
|
+
// Cart not found — guide the buyer to create a new one
|
|
176
|
+
return redirect("/cart");
|
|
177
|
+
}
|
|
178
|
+
if (cart.status !== "ACTIVE") {
|
|
179
|
+
if (cart.completedOrder) {
|
|
180
|
+
// Render the order confirmation page off the data you already have
|
|
181
|
+
return redirect(`/order/${cart.completedOrder.accessToken}`);
|
|
182
|
+
}
|
|
183
|
+
// Abandoned / expired — start a fresh cart
|
|
184
|
+
return redirect("/cart/new");
|
|
185
|
+
}
|
|
186
|
+
// Render the checkout form normally
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Additive — every existing query that selects the shared `Cart` fragment now sees the two new fields automatically. No breaking change.
|
|
190
|
+
|
|
191
|
+
`@doswiftly/storefront-operations` bumped to keep linked parity — schema sync delivers the new fields and the `CartStatus` enum.
|
|
192
|
+
|
|
193
|
+
- f4efab9: Add `ShopConfigFields` fragment + `query ShopConfig` for `<StorefrontProvider>` setup.
|
|
194
|
+
|
|
195
|
+
`<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react` expects a `ShopConfig` payload with a specific shape: currency setup (including `localeToCurrencyMap`), language setup, and bot protection. Until now the storefront had to hand-write the field selection, and it was easy to miss `localeToCurrencyMap` (used internally by the SDK for browser-locale-based currency detection) or to add an extra field that didn't match the `ShopConfig` interface.
|
|
196
|
+
|
|
197
|
+
**New**
|
|
198
|
+
- `fragment ShopConfigFields on Shop` — minimal selection that matches the `ShopConfig` interface 1:1.
|
|
199
|
+
- `query ShopConfig { shop { ...ShopConfigFields } }` — ready-to-use query for the provider.
|
|
200
|
+
|
|
201
|
+
**Example**
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const SHOP_CONFIG_QUERY = /* GraphQL */ `
|
|
205
|
+
query ShopConfig {
|
|
206
|
+
shop {
|
|
207
|
+
...ShopConfigFields
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
`;
|
|
211
|
+
|
|
212
|
+
// In a Server Component:
|
|
213
|
+
const { data } = await execute(SHOP_CONFIG_QUERY);
|
|
214
|
+
return <StorefrontProvider shopData={data.shop}>{children}</StorefrontProvider>;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Use the larger `Shop` fragment + `query Shop` when you also need branding / contact / business hours for your UI; use `ShopConfig` when you only need to bootstrap the provider.
|
|
218
|
+
|
|
219
|
+
Additive — no breaking change.
|
|
220
|
+
|
|
221
|
+
`@doswiftly/storefront-sdk` bumped to keep linked parity — no code change.
|
|
222
|
+
|
|
223
|
+
### Patch Changes
|
|
224
|
+
|
|
225
|
+
- 7ce8ac4: Clarify how `apiUrl` and `shopSlug` are configured.
|
|
226
|
+
|
|
227
|
+
`createStorefrontClient` and `<StorefrontProvider>` take `apiUrl` and `shopSlug` as **explicit `config`** — the SDK does not read environment variables, sniff hostnames, or inspect request headers. The storefront supplies the values; the SDK uses them verbatim.
|
|
228
|
+
|
|
229
|
+
Scaffolded storefronts ship a config helper (`lib/graphql/config.ts`) that resolves the two values from these sources, in order:
|
|
230
|
+
1. `doswiftly.config.ts` (preferred — committed file generated at `doswiftly init`)
|
|
231
|
+
2. `NEXT_PUBLIC_API_URL` + `NEXT_PUBLIC_SHOP_SLUG` (fallback, used for local development)
|
|
232
|
+
3. `http://localhost:8000` + `demo-shop` (defaults — smoke test only)
|
|
233
|
+
|
|
234
|
+
Scratch-built storefronts can skip the helper and pass values into `config={}` directly.
|
|
235
|
+
|
|
236
|
+
**What's new**
|
|
237
|
+
- `@doswiftly/storefront-sdk` README: new `## Configuration` section between `## Installation` and `## Quick Start`. Documents the explicit-config requirement, the three-source resolver shipped with scaffolded storefronts, and when env-var wiring actually matters.
|
|
238
|
+
- `@doswiftly/storefront-operations` `AGENTS.md`: new `### Configuration sources` convention inside `## Critical conventions — DO NOT hallucinate`. AI assistants now prefer `doswiftly.config.ts` and only fall back to the canonical env-var names.
|
|
239
|
+
|
|
240
|
+
Documentation only — no code change.
|
|
241
|
+
|
|
3
242
|
## 15.1.0
|
|
4
243
|
|
|
5
244
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -163,6 +163,7 @@ full executable body of each operation.
|
|
|
163
163
|
| Operation | Description |
|
|
164
164
|
| --- | --- |
|
|
165
165
|
| `Shop` | Returns shop configuration: name, base + supported currencies, supported locales, branding (logo, colors, fonts, social links), contact info, active payment methods, brand metadata, money format template, and the list of countries the shop ships to. Public; no auth required. Call once per session and cache — almost everything else is contextualized by the shop returned here. |
|
|
166
|
+
| `ShopConfig` | Minimal Shop payload for `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Returns exactly the fields the SDK's `ShopConfig` interface declares — currency setup (with `localeToCurrencyMap` for browser-locale-based currency detection), language setup, and bot protection. Cache for the session; refetch when the merchant updates currency / language settings or you want to pick up new bot-protection rules. |
|
|
166
167
|
|
|
167
168
|
#### Products
|
|
168
169
|
|
|
@@ -476,7 +477,7 @@ full executable body of each operation.
|
|
|
476
477
|
|
|
477
478
|
| Fragment | On Type | Description |
|
|
478
479
|
| --- | --- | --- |
|
|
479
|
-
| `CartCost` | `CartCost` | Cart-level totals — subtotal, total, tax, duty, checkout charge. Spread inside the `Cart` fragment. |
|
|
480
|
+
| `CartCost` | `CartCost` | Cart-level totals — subtotal, total, tax, duty, discount, shipping, checkout charge. Spread inside the `Cart` fragment. |
|
|
480
481
|
| `CartLineCost` | `CartLineCost` | Per-line cost breakdown — unit price, line subtotal/total, compare-at unit price (for showing strikethroughs). Spread inside `CartLine`. |
|
|
481
482
|
| `AttributeSelection` | `AttributeSelection` | Typed snapshot of a customer-filled product attribute (configurator selection) on a cart line. Includes the chosen option / text value, fillingMode, billingMode, surcharge, tax class, and any linked variant. Distinct from `CartLine.attributes` which holds raw key-value line item properties (free-form, untyped). |
|
|
482
483
|
| `CartLine` | `CartLine` | A single line in the cart — variant + quantity + per-line cost, plus dual attribute storage: `attributes[]` for free-form key-value properties (gift wrap, engraving notes), `attributeSelections[]` for typed configurator answers. |
|
|
@@ -501,6 +502,7 @@ full executable body of each operation.
|
|
|
501
502
|
| `BotProtectionProvider` | `BotProtectionProviderInfo` | Bot-protection provider config (provider name, site key, script URL) for storefront-side challenge widgets. |
|
|
502
503
|
| `BotProtection` | `BotProtectionInfo` | Bot-protection setup for the shop — primary + fallback provider, and the list of `protectedOperations` (mutation names that require a challenge token). Spread inside `Shop`. |
|
|
503
504
|
| `Shop` | `Shop` | The shop itself — name, primary domain, currencies + locales, branding, contact info, business hours, bot-protection config. Spread on the root `shop` query; cache for the session. |
|
|
505
|
+
| `ShopConfigFields` | `Shop` | Minimal Shop fields consumed by `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Spread this in your `shop` query to get a response shape that matches the SDK `ShopConfig` interface 1:1 — no manual field selection, no drift when the SDK adds optional fields. Use the larger `Shop` fragment when you also need branding / contact / business hours for your UI. |
|
|
504
506
|
|
|
505
507
|
#### Payment Methods
|
|
506
508
|
|
package/fragments.graphql
CHANGED
|
@@ -347,7 +347,7 @@ fragment Order on Order {
|
|
|
347
347
|
# Cart
|
|
348
348
|
# ============================================
|
|
349
349
|
|
|
350
|
-
# Cart-level totals — subtotal, total, tax, duty, checkout charge. Spread inside the `Cart` fragment.
|
|
350
|
+
# Cart-level totals — subtotal, total, tax, duty, discount, shipping, checkout charge. Spread inside the `Cart` fragment.
|
|
351
351
|
fragment CartCost on CartCost {
|
|
352
352
|
total {
|
|
353
353
|
...Money
|
|
@@ -364,6 +364,12 @@ fragment CartCost on CartCost {
|
|
|
364
364
|
checkoutCharge {
|
|
365
365
|
...Money
|
|
366
366
|
}
|
|
367
|
+
totalDiscount {
|
|
368
|
+
...Money
|
|
369
|
+
}
|
|
370
|
+
totalShipping {
|
|
371
|
+
...Money
|
|
372
|
+
}
|
|
367
373
|
}
|
|
368
374
|
|
|
369
375
|
# Per-line cost breakdown — unit price, line subtotal/total, compare-at unit price (for showing strikethroughs). Spread inside `CartLine`.
|
|
@@ -505,6 +511,15 @@ fragment Cart on Cart {
|
|
|
505
511
|
requiresShipping
|
|
506
512
|
createdAt
|
|
507
513
|
updatedAt
|
|
514
|
+
status
|
|
515
|
+
completedOrder {
|
|
516
|
+
id
|
|
517
|
+
orderNumber
|
|
518
|
+
accessToken
|
|
519
|
+
status
|
|
520
|
+
paymentStatus
|
|
521
|
+
fulfillmentStatus
|
|
522
|
+
}
|
|
508
523
|
}
|
|
509
524
|
|
|
510
525
|
# Shipping method selected on a cart (D8 term unification — wcześniej ShippingRate). Returned przez `cart.selectedShippingMethod` po `cartSelectShippingMethod` mutation.
|
|
@@ -661,6 +676,21 @@ fragment Shop on Shop {
|
|
|
661
676
|
}
|
|
662
677
|
}
|
|
663
678
|
|
|
679
|
+
# Minimal Shop fields consumed by `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Spread this in your `shop` query to get a response shape that matches the SDK `ShopConfig` interface 1:1 — no manual field selection, no drift when the SDK adds optional fields. Use the larger `Shop` fragment when you also need branding / contact / business hours for your UI.
|
|
680
|
+
fragment ShopConfigFields on Shop {
|
|
681
|
+
currencyCode
|
|
682
|
+
supportedCurrencies
|
|
683
|
+
localeToCurrencyMap {
|
|
684
|
+
locale
|
|
685
|
+
currency
|
|
686
|
+
}
|
|
687
|
+
defaultLanguage
|
|
688
|
+
supportedLanguages
|
|
689
|
+
botProtection {
|
|
690
|
+
...BotProtection
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
664
694
|
# ============================================
|
|
665
695
|
# Payment Methods
|
|
666
696
|
# ============================================
|
package/llms-full.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# DoSwiftly Storefront Operations — Full Reference
|
|
2
2
|
|
|
3
|
-
> Schema version: **
|
|
4
|
-
>
|
|
3
|
+
> Schema version: **16.0.0**
|
|
4
|
+
> 52 queries · 40 mutations · 102 fragments
|
|
5
5
|
|
|
6
6
|
Auto-generated from `.graphql` source files. Do not edit by hand — this file is
|
|
7
7
|
regenerated on every release to match the published schema.
|
|
@@ -37,6 +37,25 @@ query Shop {
|
|
|
37
37
|
}
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
### Query: `ShopConfig`
|
|
41
|
+
|
|
42
|
+
**Section**: Shop
|
|
43
|
+
|
|
44
|
+
**Description**: Minimal Shop payload for `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Returns exactly the fields the SDK's `ShopConfig` interface declares — currency setup (with `localeToCurrencyMap` for browser-locale-based currency detection), language setup, and bot protection. Cache for the session; refetch when the merchant updates currency / language settings or you want to pick up new bot-protection rules.
|
|
45
|
+
|
|
46
|
+
**Variables**: none
|
|
47
|
+
|
|
48
|
+
**Fragments used**: `ShopConfigFields`
|
|
49
|
+
|
|
50
|
+
**GraphQL**:
|
|
51
|
+
```graphql
|
|
52
|
+
query ShopConfig {
|
|
53
|
+
shop {
|
|
54
|
+
...ShopConfigFields
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
40
59
|
### Query: `Product`
|
|
41
60
|
|
|
42
61
|
**Section**: Products
|
|
@@ -2920,7 +2939,7 @@ fragment Order on Order {
|
|
|
2920
2939
|
|
|
2921
2940
|
**Section**: Cart
|
|
2922
2941
|
|
|
2923
|
-
**Description**: Cart-level totals — subtotal, total, tax, duty, checkout charge. Spread inside the `Cart` fragment.
|
|
2942
|
+
**Description**: Cart-level totals — subtotal, total, tax, duty, discount, shipping, checkout charge. Spread inside the `Cart` fragment.
|
|
2924
2943
|
|
|
2925
2944
|
**Uses fragments**: `Money`
|
|
2926
2945
|
|
|
@@ -2942,6 +2961,12 @@ fragment CartCost on CartCost {
|
|
|
2942
2961
|
checkoutCharge {
|
|
2943
2962
|
...Money
|
|
2944
2963
|
}
|
|
2964
|
+
totalDiscount {
|
|
2965
|
+
...Money
|
|
2966
|
+
}
|
|
2967
|
+
totalShipping {
|
|
2968
|
+
...Money
|
|
2969
|
+
}
|
|
2945
2970
|
}
|
|
2946
2971
|
```
|
|
2947
2972
|
|
|
@@ -3147,6 +3172,15 @@ fragment Cart on Cart {
|
|
|
3147
3172
|
requiresShipping
|
|
3148
3173
|
createdAt
|
|
3149
3174
|
updatedAt
|
|
3175
|
+
status
|
|
3176
|
+
completedOrder {
|
|
3177
|
+
id
|
|
3178
|
+
orderNumber
|
|
3179
|
+
accessToken
|
|
3180
|
+
status
|
|
3181
|
+
paymentStatus
|
|
3182
|
+
fulfillmentStatus
|
|
3183
|
+
}
|
|
3150
3184
|
}
|
|
3151
3185
|
```
|
|
3152
3186
|
|
|
@@ -3406,6 +3440,31 @@ fragment Shop on Shop {
|
|
|
3406
3440
|
}
|
|
3407
3441
|
```
|
|
3408
3442
|
|
|
3443
|
+
### Fragment: `ShopConfigFields` on `Shop`
|
|
3444
|
+
|
|
3445
|
+
**Section**: Shop
|
|
3446
|
+
|
|
3447
|
+
**Description**: Minimal Shop fields consumed by `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Spread this in your `shop` query to get a response shape that matches the SDK `ShopConfig` interface 1:1 — no manual field selection, no drift when the SDK adds optional fields. Use the larger `Shop` fragment when you also need branding / contact / business hours for your UI.
|
|
3448
|
+
|
|
3449
|
+
**Uses fragments**: `BotProtection`
|
|
3450
|
+
|
|
3451
|
+
**GraphQL**:
|
|
3452
|
+
```graphql
|
|
3453
|
+
fragment ShopConfigFields on Shop {
|
|
3454
|
+
currencyCode
|
|
3455
|
+
supportedCurrencies
|
|
3456
|
+
localeToCurrencyMap {
|
|
3457
|
+
locale
|
|
3458
|
+
currency
|
|
3459
|
+
}
|
|
3460
|
+
defaultLanguage
|
|
3461
|
+
supportedLanguages
|
|
3462
|
+
botProtection {
|
|
3463
|
+
...BotProtection
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
```
|
|
3467
|
+
|
|
3409
3468
|
### Fragment: `PaymentMethod` on `PaymentMethod`
|
|
3410
3469
|
|
|
3411
3470
|
**Section**: Payment Methods
|
package/operations.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion": "
|
|
2
|
+
"schemaVersion": "16.0.0",
|
|
3
3
|
"queries": [
|
|
4
4
|
{
|
|
5
5
|
"name": "Shop",
|
|
@@ -12,6 +12,17 @@
|
|
|
12
12
|
],
|
|
13
13
|
"body": "query Shop {\n shop {\n ...Shop\n }\n}"
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
"name": "ShopConfig",
|
|
17
|
+
"kind": "query",
|
|
18
|
+
"section": "Shop",
|
|
19
|
+
"description": "Minimal Shop payload for `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Returns exactly the fields the SDK's `ShopConfig` interface declares — currency setup (with `localeToCurrencyMap` for browser-locale-based currency detection), language setup, and bot protection. Cache for the session; refetch when the merchant updates currency / language settings or you want to pick up new bot-protection rules.",
|
|
20
|
+
"variables": [],
|
|
21
|
+
"fragmentRefs": [
|
|
22
|
+
"ShopConfigFields"
|
|
23
|
+
],
|
|
24
|
+
"body": "query ShopConfig {\n shop {\n ...ShopConfigFields\n }\n}"
|
|
25
|
+
},
|
|
15
26
|
{
|
|
16
27
|
"name": "Product",
|
|
17
28
|
"kind": "query",
|
|
@@ -2072,12 +2083,12 @@
|
|
|
2072
2083
|
"name": "CartCost",
|
|
2073
2084
|
"kind": "fragment",
|
|
2074
2085
|
"section": "Cart",
|
|
2075
|
-
"description": "Cart-level totals — subtotal, total, tax, duty, checkout charge. Spread inside the `Cart` fragment.",
|
|
2086
|
+
"description": "Cart-level totals — subtotal, total, tax, duty, discount, shipping, checkout charge. Spread inside the `Cart` fragment.",
|
|
2076
2087
|
"variables": [],
|
|
2077
2088
|
"fragmentRefs": [
|
|
2078
2089
|
"Money"
|
|
2079
2090
|
],
|
|
2080
|
-
"body": "fragment CartCost on CartCost {\n total {\n ...Money\n }\n subtotal {\n ...Money\n }\n totalTax {\n ...Money\n }\n totalDuty {\n ...Money\n }\n checkoutCharge {\n ...Money\n }\n}",
|
|
2091
|
+
"body": "fragment CartCost on CartCost {\n total {\n ...Money\n }\n subtotal {\n ...Money\n }\n totalTax {\n ...Money\n }\n totalDuty {\n ...Money\n }\n checkoutCharge {\n ...Money\n }\n totalDiscount {\n ...Money\n }\n totalShipping {\n ...Money\n }\n}",
|
|
2081
2092
|
"onType": "CartCost"
|
|
2082
2093
|
},
|
|
2083
2094
|
{
|
|
@@ -2166,7 +2177,7 @@
|
|
|
2166
2177
|
"MailingAddress",
|
|
2167
2178
|
"PageInfo"
|
|
2168
2179
|
],
|
|
2169
|
-
"body": "fragment Cart on Cart {\n id\n checkoutUrl\n totalQuantity\n cost {\n ...CartCost\n }\n lines(first: 100) {\n edges {\n cursor\n node {\n ... on CartLine {\n ...CartLine\n }\n }\n }\n nodes {\n ... on CartLine {\n ...CartLine\n }\n }\n pageInfo {\n ...PageInfo\n }\n totalCount\n }\n buyerIdentity {\n ...CartBuyerIdentity\n }\n discountCodes {\n ...CartDiscountCode\n }\n discountAllocations {\n ...CartDiscountAllocation\n }\n note\n attributes {\n key\n value\n }\n email\n phone\n shippingAddress {\n ...MailingAddress\n }\n billingAddress {\n ...MailingAddress\n }\n selectedShippingMethod {\n ...CartShippingMethod\n }\n selectedPaymentMethod {\n ...CartSelectedPaymentMethod\n }\n appliedGiftCards {\n ...CartAppliedGiftCard\n }\n requiresShipping\n createdAt\n updatedAt\n}",
|
|
2180
|
+
"body": "fragment Cart on Cart {\n id\n checkoutUrl\n totalQuantity\n cost {\n ...CartCost\n }\n lines(first: 100) {\n edges {\n cursor\n node {\n ... on CartLine {\n ...CartLine\n }\n }\n }\n nodes {\n ... on CartLine {\n ...CartLine\n }\n }\n pageInfo {\n ...PageInfo\n }\n totalCount\n }\n buyerIdentity {\n ...CartBuyerIdentity\n }\n discountCodes {\n ...CartDiscountCode\n }\n discountAllocations {\n ...CartDiscountAllocation\n }\n note\n attributes {\n key\n value\n }\n email\n phone\n shippingAddress {\n ...MailingAddress\n }\n billingAddress {\n ...MailingAddress\n }\n selectedShippingMethod {\n ...CartShippingMethod\n }\n selectedPaymentMethod {\n ...CartSelectedPaymentMethod\n }\n appliedGiftCards {\n ...CartAppliedGiftCard\n }\n requiresShipping\n createdAt\n updatedAt\n status\n completedOrder {\n id\n orderNumber\n accessToken\n status\n paymentStatus\n fulfillmentStatus\n }\n}",
|
|
2170
2181
|
"onType": "Cart"
|
|
2171
2182
|
},
|
|
2172
2183
|
{
|
|
@@ -2306,6 +2317,18 @@
|
|
|
2306
2317
|
"body": "fragment Shop on Shop {\n id\n name\n description\n primaryDomain {\n host\n url\n isSslEnabled\n }\n currencyCode\n supportedCurrencies\n paymentCurrencies\n defaultLanguage\n supportedLanguages\n logo {\n ...Image\n }\n contactEmail\n contactPhone\n address {\n ...ShopAddress\n }\n businessHours {\n ...BusinessHour\n }\n branding {\n ...ShopBranding\n }\n botProtection {\n ...BotProtection\n }\n}",
|
|
2307
2318
|
"onType": "Shop"
|
|
2308
2319
|
},
|
|
2320
|
+
{
|
|
2321
|
+
"name": "ShopConfigFields",
|
|
2322
|
+
"kind": "fragment",
|
|
2323
|
+
"section": "Shop",
|
|
2324
|
+
"description": "Minimal Shop fields consumed by `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Spread this in your `shop` query to get a response shape that matches the SDK `ShopConfig` interface 1:1 — no manual field selection, no drift when the SDK adds optional fields. Use the larger `Shop` fragment when you also need branding / contact / business hours for your UI.",
|
|
2325
|
+
"variables": [],
|
|
2326
|
+
"fragmentRefs": [
|
|
2327
|
+
"BotProtection"
|
|
2328
|
+
],
|
|
2329
|
+
"body": "fragment ShopConfigFields on Shop {\n currencyCode\n supportedCurrencies\n localeToCurrencyMap {\n locale\n currency\n }\n defaultLanguage\n supportedLanguages\n botProtection {\n ...BotProtection\n }\n}",
|
|
2330
|
+
"onType": "Shop"
|
|
2331
|
+
},
|
|
2309
2332
|
{
|
|
2310
2333
|
"name": "PaymentMethod",
|
|
2311
2334
|
"kind": "fragment",
|
package/package.json
CHANGED
package/queries.graphql
CHANGED
|
@@ -14,6 +14,13 @@ query Shop {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
# Minimal Shop payload for `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Returns exactly the fields the SDK's `ShopConfig` interface declares — currency setup (with `localeToCurrencyMap` for browser-locale-based currency detection), language setup, and bot protection. Cache for the session; refetch when the merchant updates currency / language settings or you want to pick up new bot-protection rules.
|
|
18
|
+
query ShopConfig {
|
|
19
|
+
shop {
|
|
20
|
+
...ShopConfigFields
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
# ============================================
|
|
18
25
|
# Products
|
|
19
26
|
# ============================================
|
package/schema.graphql
CHANGED
|
@@ -903,6 +903,11 @@ type Cart implements Node {
|
|
|
903
903
|
"""
|
|
904
904
|
checkoutUrl: URL
|
|
905
905
|
|
|
906
|
+
"""
|
|
907
|
+
The order that this cart converted into. Populated only when `status` is `CONVERTED` — null on every other status. Use this to render the order confirmation page (subtotals, accessToken for guest tracking) directly off the cart you already loaded, without a second `orderByToken` round-trip.
|
|
908
|
+
"""
|
|
909
|
+
completedOrder: Order
|
|
910
|
+
|
|
906
911
|
"""
|
|
907
912
|
Cost breakdown for the cart (subtotal, tax, shipping, discount, grand total).
|
|
908
913
|
"""
|
|
@@ -965,6 +970,11 @@ type Cart implements Node {
|
|
|
965
970
|
"""
|
|
966
971
|
shippingAddress: MailingAddress
|
|
967
972
|
|
|
973
|
+
"""
|
|
974
|
+
Lifecycle status — `ACTIVE` for the editable working cart, terminal otherwise. Check this on SSR before rendering the checkout form: a non-`ACTIVE` cart should redirect (typically to the order confirmation when `completedOrder` is populated) instead of presenting a form whose first mutation fails with `CartErrorCode.ALREADY_COMPLETED`.
|
|
975
|
+
"""
|
|
976
|
+
status: CartStatus!
|
|
977
|
+
|
|
968
978
|
"""
|
|
969
979
|
Sum of `quantity` across all lines — the badge number for the cart icon.
|
|
970
980
|
"""
|
|
@@ -1664,6 +1674,17 @@ type CartShippingMethod {
|
|
|
1664
1674
|
title: String!
|
|
1665
1675
|
}
|
|
1666
1676
|
|
|
1677
|
+
"""
|
|
1678
|
+
Cart lifecycle status. `ACTIVE` is the only editable state — every other value is terminal and rejects mutations with `CartErrorCode.ALREADY_COMPLETED`. `CONVERTED` carries an associated `completedOrder`; query that to redirect the buyer to their order confirmation. `EXPIRED` / `ABANDONED` are cleanup states with no order; create a fresh cart. `RECOVERED` is a previously-abandoned cart that the buyer returned to via a recovery link.
|
|
1679
|
+
"""
|
|
1680
|
+
enum CartStatus {
|
|
1681
|
+
ABANDONED
|
|
1682
|
+
ACTIVE
|
|
1683
|
+
CONVERTED
|
|
1684
|
+
EXPIRED
|
|
1685
|
+
RECOVERED
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1667
1688
|
"""Result of `cartUpdateAttributes`."""
|
|
1668
1689
|
type CartUpdateAttributesPayload {
|
|
1669
1690
|
"""The updated cart on success."""
|