@godaddy/gd-commerce-storefront 0.7.0 → 0.8.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/README.md +10 -6
- package/dist/index.js +40 -3
- package/docs/server-api.md +10 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -525,12 +525,16 @@ mutation methods apply only to the connected store; sample cart data is internal
|
|
|
525
525
|
without `sampleProducts`, and direct product-detail visits, show the unconnected state.
|
|
526
526
|
Sample grids and drawers have the attribute `data-commerce-source="sample"`.
|
|
527
527
|
|
|
528
|
-
The provider reads configuration on mount and focus
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
528
|
+
The provider reads configuration on mount and focus. While the page is visible and the state is
|
|
529
|
+
`unbound` or `connecting`, it also polls every five seconds for five minutes after the page loads,
|
|
530
|
+
then every minute, and stops thirty minutes after load. Reloading, retrying or a change in the
|
|
531
|
+
reported state starts it again. A page still `connecting` when polling stops shows an error with
|
|
532
|
+
"Retry connection". The first
|
|
533
|
+
failed refresh hides samples and clears the sample cart; a later `unbound` response starts an
|
|
534
|
+
empty sample cart. While connecting, refresh failures keep the connecting
|
|
535
|
+
state for up to 60 seconds before showing the error. Once polling slows to every minute, the next
|
|
536
|
+
failure is already 60 seconds after the last success, so it shows the error at once. Polling
|
|
537
|
+
stops when the state is `ready`; focus and explicit retry still refresh configuration.
|
|
534
538
|
|
|
535
539
|
Use a server that reports connection state before you enable `sampleProducts`. Successful
|
|
536
540
|
config responses without `state` still mean ready. A server that does not report `unbound`
|
package/dist/index.js
CHANGED
|
@@ -212,6 +212,11 @@ function useMoney() {
|
|
|
212
212
|
return useCallback((value, currency = currencyCode) => money(value, currency, locale), [locale, currencyCode]);
|
|
213
213
|
}
|
|
214
214
|
const CONNECTING_FAILURE_GRACE_MS = 6e4;
|
|
215
|
+
/** Polls every five seconds for five minutes after the page loads, then every minute, and stops at thirty. */
|
|
216
|
+
const FAST_POLL_FOR_MS = 5 * 6e4;
|
|
217
|
+
const STOP_POLLING_AT_MS = 30 * 6e4;
|
|
218
|
+
/** A failed retry keeps showing connecting this long so the click visibly does something. */
|
|
219
|
+
const RETRY_FEEDBACK_MS = 1e3;
|
|
215
220
|
/** `locale` as a canonical tag, or `en-US` when it is not a valid one, so one bad prop cannot break every price. */
|
|
216
221
|
function resolveLocale(locale) {
|
|
217
222
|
if (!locale) return "en-US";
|
|
@@ -250,6 +255,14 @@ async function loadConfig(signal) {
|
|
|
250
255
|
}
|
|
251
256
|
function CommerceProvider({ children, catalogPath = "/shop", productPath = "/products", checkoutSuccessPath, theme = {}, getSwatch, locale, onItemAdded, onEvent }) {
|
|
252
257
|
const resolvedLocale = useMemo(() => resolveLocale(locale), [locale]);
|
|
258
|
+
const [pollingSince, setPollingSince] = useState(Date.now);
|
|
259
|
+
const [pollingStopped, setPollingStopped] = useState(false);
|
|
260
|
+
const [retrying, setRetrying] = useState(false);
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
setPollingStopped(false);
|
|
263
|
+
const timeout = setTimeout(() => setPollingStopped(true), pollingSince + STOP_POLLING_AT_MS - Date.now());
|
|
264
|
+
return () => clearTimeout(timeout);
|
|
265
|
+
}, [pollingSince]);
|
|
253
266
|
const config = useQuery({
|
|
254
267
|
retry: false,
|
|
255
268
|
queryKey: ["commerce", "configuration"],
|
|
@@ -257,12 +270,26 @@ function CommerceProvider({ children, catalogPath = "/shop", productPath = "/pro
|
|
|
257
270
|
staleTime: 3e4,
|
|
258
271
|
refetchOnMount: "always",
|
|
259
272
|
refetchOnWindowFocus: "always",
|
|
260
|
-
refetchInterval: (query) =>
|
|
273
|
+
refetchInterval: (query) => {
|
|
274
|
+
const waiting = query.state.data?.state === "unbound" || query.state.data?.state === "connecting";
|
|
275
|
+
const elapsed = Date.now() - pollingSince;
|
|
276
|
+
if (!waiting || elapsed >= STOP_POLLING_AT_MS) return false;
|
|
277
|
+
return elapsed < FAST_POLL_FOR_MS ? 5e3 : 6e4;
|
|
278
|
+
},
|
|
261
279
|
refetchIntervalInBackground: false
|
|
262
280
|
});
|
|
281
|
+
const [reported, setReported] = useState(config.data?.state);
|
|
282
|
+
if (reported !== config.data?.state) {
|
|
283
|
+
setReported(config.data?.state);
|
|
284
|
+
setPollingSince(Date.now());
|
|
285
|
+
setPollingStopped(false);
|
|
286
|
+
}
|
|
263
287
|
const holdConnecting = config.isError && config.data?.state === "connecting" && config.errorUpdatedAt - config.dataUpdatedAt < CONNECTING_FAILURE_GRACE_MS;
|
|
264
288
|
let connection = config.data?.state ?? "loading";
|
|
265
289
|
if (config.isError) connection = holdConnecting ? "connecting" : "error";
|
|
290
|
+
const stalled = pollingStopped && connection === "connecting";
|
|
291
|
+
if (stalled) connection = "error";
|
|
292
|
+
if (retrying) connection = "connecting";
|
|
266
293
|
return /* @__PURE__ */ jsx(BoundCommerceProvider, {
|
|
267
294
|
config: {
|
|
268
295
|
cartScope: "",
|
|
@@ -273,9 +300,19 @@ function CommerceProvider({ children, catalogPath = "/shop", productPath = "/pro
|
|
|
273
300
|
checkoutSuccessPath
|
|
274
301
|
},
|
|
275
302
|
connection,
|
|
276
|
-
connectionError: connection
|
|
303
|
+
connectionError: connection !== "error" ? null : stalled ? "The store is taking too long to connect." : message(config.error),
|
|
277
304
|
retryConnection: () => {
|
|
278
|
-
|
|
305
|
+
const started = Date.now();
|
|
306
|
+
setPollingSince(started);
|
|
307
|
+
if (connection !== "error") {
|
|
308
|
+
config.refetch();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
setRetrying(true);
|
|
312
|
+
config.refetch().then(async (result) => {
|
|
313
|
+
if (result.isError) await new Promise((resolve) => setTimeout(resolve, started + RETRY_FEEDBACK_MS - Date.now()));
|
|
314
|
+
setRetrying(false);
|
|
315
|
+
});
|
|
279
316
|
},
|
|
280
317
|
theme,
|
|
281
318
|
getSwatch,
|
package/docs/server-api.md
CHANGED
|
@@ -134,9 +134,14 @@ live data only when the deployed server reports a new state. If a host's deploym
|
|
|
134
134
|
state from deployment configuration, a deployed site keeps showing samples until that
|
|
135
135
|
configuration is updated, for example by publishing again.
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
connecting
|
|
141
|
-
|
|
137
|
+
While the page is visible and the state is `unbound` or `connecting`, the storefront polls every
|
|
138
|
+
five seconds for five minutes after the page loads, then every minute, and stops thirty minutes
|
|
139
|
+
after load. It also refreshes on mount and focus, and reloading or retrying starts polling again. A
|
|
140
|
+
page still `connecting` when polling stops shows an error with a retry button, so finish connecting
|
|
141
|
+
well within thirty minutes. A failed refresh immediately hides
|
|
142
|
+
samples, without automatic request retries. While the last response was `connecting`, refresh
|
|
143
|
+
failures keep the connecting state for up to 60 seconds, so a host restart during connection does
|
|
144
|
+
not flash an error. This holds only in the first five minutes; after that, polls are a minute
|
|
145
|
+
apart, and the first failure reports the error. Polling continues, and a longer failure reports
|
|
146
|
+
the error. Aborted configuration requests cannot overwrite newer responses.
|
|
142
147
|
Release server and client support before using the `sampleProducts` prop. No new endpoint is required.
|