@shopify/hydrogen 2023.7.3 → 2023.7.4

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.
@@ -1,9 +1,10 @@
1
1
  import { createStorefrontClient as createStorefrontClient$1, SHOPIFY_STOREFRONT_ID_HEADER, getShopifyCookies, SHOPIFY_Y, SHOPIFY_STOREFRONT_Y_HEADER, SHOPIFY_S, SHOPIFY_STOREFRONT_S_HEADER, flattenConnection } from '@shopify/hydrogen-react';
2
2
  export { AnalyticsEventName, AnalyticsPageType, ExternalVideo, IMAGE_FRAGMENT, Image, MediaFile, ModelViewer, Money, ShopPayButton, ShopifySalesChannel, Video, flattenConnection, getClientBrowserParameters, getShopifyCookies, parseGid, parseMetafield, sendShopifyAnalytics, storefrontApiCustomScalars, useLoadScript, useMoney, useShopifyCookies } from '@shopify/hydrogen-react';
3
3
  import { redirect } from '@remix-run/server-runtime';
4
- import { lazy, useMemo, createElement, Suspense, Fragment } from 'react';
4
+ import { lazy, createContext, forwardRef, useMemo, createElement, Suspense, Fragment, useState, useEffect, useContext } from 'react';
5
5
  import { useMatches, useLocation, useNavigation, Link, useFetcher } from '@remix-run/react';
6
- import { jsxs, jsx } from 'react/jsx-runtime';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+ import cspBuilder from 'content-security-policy-builder';
7
8
 
8
9
  // src/storefront.ts
9
10
 
@@ -332,7 +333,7 @@ var warnOnce = (string) => {
332
333
  };
333
334
 
334
335
  // src/version.ts
335
- var LIB_VERSION = "2023.7.3";
336
+ var LIB_VERSION = "2023.7.4";
336
337
 
337
338
  // src/storefront.ts
338
339
  var StorefrontApiError = class extends Error {
@@ -1247,7 +1248,7 @@ function Pagination({
1247
1248
  replace: true
1248
1249
  }) : null;
1249
1250
  },
1250
- [hasNextPage, nextPageUrl]
1251
+ [hasNextPage, nextPageUrl, state]
1251
1252
  );
1252
1253
  const PreviousLink = useMemo(
1253
1254
  () => function PrevLink(props) {
@@ -1259,7 +1260,7 @@ function Pagination({
1259
1260
  replace: true
1260
1261
  }) : null;
1261
1262
  },
1262
- [hasPreviousPage, previousPageUrl]
1263
+ [hasPreviousPage, previousPageUrl, state]
1263
1264
  );
1264
1265
  return children({
1265
1266
  state,
@@ -1278,42 +1279,41 @@ function usePagination(connection) {
1278
1279
  const params = new URLSearchParams(search);
1279
1280
  const direction = params.get("direction");
1280
1281
  const isPrevious = direction === "previous";
1281
- const nodes = useMemo(() => {
1282
- if (!state || !state?.nodes) {
1283
- return flattenConnection(connection);
1284
- }
1285
- if (isPrevious) {
1286
- return [...flattenConnection(connection), ...state.nodes];
1287
- } else {
1288
- return [...state.nodes, ...flattenConnection(connection)];
1289
- }
1290
- }, [state, connection]);
1291
- const currentPageInfo = useMemo(() => {
1292
- let pageStartCursor = state?.pageInfo?.startCursor === void 0 ? connection.pageInfo.startCursor : state.pageInfo.startCursor;
1293
- let pageEndCursor = state?.pageInfo?.endCursor === void 0 ? connection.pageInfo.endCursor : state.pageInfo.endCursor;
1282
+ const [nodes, setNodes] = useState(flattenConnection(connection));
1283
+ const [currentPageInfo, setCurrentPageInfo] = useState({
1284
+ startCursor: connection.pageInfo.startCursor,
1285
+ endCursor: connection.pageInfo.endCursor,
1286
+ hasPreviousPage: connection.pageInfo.hasPreviousPage,
1287
+ hasNextPage: connection.pageInfo.hasNextPage
1288
+ });
1289
+ useEffect(() => {
1294
1290
  if (state?.nodes) {
1295
- if (isPrevious) {
1296
- pageStartCursor = connection.pageInfo.startCursor;
1297
- } else {
1298
- pageEndCursor = connection.pageInfo.endCursor;
1291
+ setNodes(
1292
+ isPrevious ? [...flattenConnection(connection), ...state.nodes] : [...state.nodes, ...flattenConnection(connection)]
1293
+ );
1294
+ }
1295
+ if (state?.pageInfo) {
1296
+ let pageStartCursor = state?.pageInfo?.startCursor === void 0 ? connection.pageInfo.startCursor : state.pageInfo.startCursor;
1297
+ let pageEndCursor = state?.pageInfo?.endCursor === void 0 ? connection.pageInfo.endCursor : state.pageInfo.endCursor;
1298
+ let previousPageExists = state?.pageInfo?.hasPreviousPage === void 0 ? connection.pageInfo.hasPreviousPage : state.pageInfo.hasPreviousPage;
1299
+ let nextPageExists = state?.pageInfo?.hasNextPage === void 0 ? connection.pageInfo.hasNextPage : state.pageInfo.hasNextPage;
1300
+ if (state?.nodes) {
1301
+ if (isPrevious) {
1302
+ pageStartCursor = connection.pageInfo.startCursor;
1303
+ previousPageExists = connection.pageInfo.hasPreviousPage;
1304
+ } else {
1305
+ pageEndCursor = connection.pageInfo.endCursor;
1306
+ nextPageExists = connection.pageInfo.hasNextPage;
1307
+ }
1299
1308
  }
1309
+ setCurrentPageInfo({
1310
+ startCursor: pageStartCursor,
1311
+ endCursor: pageEndCursor,
1312
+ hasPreviousPage: previousPageExists,
1313
+ hasNextPage: nextPageExists
1314
+ });
1300
1315
  }
1301
- const previousPageExists = state?.pageInfo?.hasPreviousPage === void 0 ? connection.pageInfo.hasPreviousPage : state.pageInfo.hasPreviousPage;
1302
- const nextPageExists = state?.pageInfo?.hasNextPage === void 0 ? connection.pageInfo.hasNextPage : state.pageInfo.hasNextPage;
1303
- return {
1304
- startCursor: pageStartCursor,
1305
- endCursor: pageEndCursor,
1306
- hasPreviousPage: previousPageExists,
1307
- hasNextPage: nextPageExists
1308
- };
1309
- }, [
1310
- isPrevious,
1311
- state,
1312
- connection.pageInfo.hasNextPage,
1313
- connection.pageInfo.hasPreviousPage,
1314
- connection.pageInfo.startCursor,
1315
- connection.pageInfo.endCursor
1316
- ]);
1316
+ }, [state, connection]);
1317
1317
  const previousPageUrl = useMemo(() => {
1318
1318
  const params2 = new URLSearchParams(search);
1319
1319
  params2.set("direction", "previous");
@@ -2056,10 +2056,14 @@ function VariantSelector({
2056
2056
  handle,
2057
2057
  options = [],
2058
2058
  variants: _variants = [],
2059
+ productPath = "products",
2059
2060
  children
2060
2061
  }) {
2061
2062
  const variants = _variants instanceof Array ? _variants : flattenConnection(_variants);
2062
- const { searchParams, path, alreadyOnProductPage } = useVariantPath(handle);
2063
+ const { searchParams, path, alreadyOnProductPage } = useVariantPath(
2064
+ handle,
2065
+ productPath
2066
+ );
2063
2067
  const optionsWithOnlyOneValue = options.filter(
2064
2068
  (option) => option?.values?.length === 1
2065
2069
  );
@@ -2121,12 +2125,13 @@ var getSelectedProductOptions = (request) => {
2121
2125
  });
2122
2126
  return selectedOptions;
2123
2127
  };
2124
- function useVariantPath(handle) {
2128
+ function useVariantPath(handle, productPath) {
2125
2129
  const { pathname, search } = useLocation();
2126
2130
  return useMemo(() => {
2127
2131
  const match = /(\/[a-zA-Z]{2}-[a-zA-Z]{2}\/)/g.exec(pathname);
2128
2132
  const isLocalePathname = match && match.length > 0;
2129
- const path = isLocalePathname ? `${match[0]}products/${handle}` : `/products/${handle}`;
2133
+ productPath = productPath.startsWith("/") ? productPath.substring(1) : productPath;
2134
+ const path = isLocalePathname ? `${match[0]}${productPath}/${handle}` : `/${productPath}/${handle}`;
2130
2135
  const searchParams = new URLSearchParams(search);
2131
2136
  return {
2132
2137
  searchParams,
@@ -2136,8 +2141,76 @@ function useVariantPath(handle) {
2136
2141
  alreadyOnProductPage: path === pathname,
2137
2142
  path
2138
2143
  };
2139
- }, [pathname, search, handle]);
2144
+ }, [pathname, search, handle, productPath]);
2145
+ }
2146
+
2147
+ // src/csp/nonce.ts
2148
+ function generateNonce() {
2149
+ return toHexString(randomUint8Array());
2150
+ }
2151
+ function randomUint8Array() {
2152
+ try {
2153
+ return crypto.getRandomValues(new Uint8Array(16));
2154
+ } catch (e) {
2155
+ return new Uint8Array(16).map(() => Math.random() * 255 | 0);
2156
+ }
2140
2157
  }
2158
+ function toHexString(byteArray) {
2159
+ return Array.from(byteArray, function(byte) {
2160
+ return ("0" + (byte & 255).toString(16)).slice(-2);
2161
+ }).join("");
2162
+ }
2163
+
2164
+ // src/csp/csp.ts
2165
+ var NonceContext = createContext(void 0);
2166
+ var NonceProvider = NonceContext.Provider;
2167
+ var useNonce = () => useContext(NonceContext);
2168
+ function createContentSecurityPolicy(directives = {}) {
2169
+ const nonce = generateNonce();
2170
+ const header = createCSPHeader(nonce, directives);
2171
+ const Provider = ({ children }) => {
2172
+ return createElement(NonceProvider, { value: nonce }, children);
2173
+ };
2174
+ return {
2175
+ nonce,
2176
+ header,
2177
+ NonceProvider: Provider
2178
+ };
2179
+ }
2180
+ function createCSPHeader(nonce, directives = {}) {
2181
+ const nonceString = `'nonce-${nonce}'`;
2182
+ const defaultDirectives = {
2183
+ baseUri: ["'self'"],
2184
+ defaultSrc: [
2185
+ "'self'",
2186
+ nonceString,
2187
+ "https://cdn.shopify.com",
2188
+ // Used for the Customer Account API
2189
+ "https://shopify.com"
2190
+ ],
2191
+ frameAncestors: ["none"],
2192
+ styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.shopify.com"],
2193
+ connectSrc: ["'self'", "https://monorail-edge.shopifysvc.com"]
2194
+ };
2195
+ {
2196
+ defaultDirectives.connectSrc = ["*"];
2197
+ }
2198
+ const combinedDirectives = Object.assign({}, defaultDirectives, directives);
2199
+ if (combinedDirectives.scriptSrc instanceof Array && !combinedDirectives.scriptSrc.includes(nonceString)) {
2200
+ combinedDirectives.scriptSrc.push(nonceString);
2201
+ } else if (combinedDirectives.defaultSrc instanceof Array && !combinedDirectives.defaultSrc.includes(nonceString)) {
2202
+ combinedDirectives.defaultSrc.push(nonceString);
2203
+ }
2204
+ return cspBuilder({
2205
+ directives: combinedDirectives
2206
+ });
2207
+ }
2208
+ var Script = forwardRef(
2209
+ (props, ref) => {
2210
+ const nonce = useNonce();
2211
+ return /* @__PURE__ */ jsx("script", { ...props, nonce, ref });
2212
+ }
2213
+ );
2141
2214
  //! @see: https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate
2142
2215
  //! @see https://shopify.dev/docs/api/storefront/latest/queries/cart
2143
2216
  //! @see: https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd
@@ -2150,6 +2223,6 @@ function useVariantPath(handle) {
2150
2223
  //! @see https://shopify.dev/docs/api/storefront/latest/mutations/cartMetafieldsSet
2151
2224
  //! @see https://shopify.dev/docs/api/storefront/2023-07/mutations/cartMetafieldDelete
2152
2225
 
2153
- export { CacheCustom, CacheLong, CacheNone, CacheShort, CartForm, InMemoryCache, Pagination, Seo, VariantSelector, cartAttributesUpdateDefault, cartBuyerIdentityUpdateDefault, cartCreateDefault, cartDiscountCodesUpdateDefault, cartGetDefault, cartGetIdDefault, cartLinesAddDefault, cartLinesRemoveDefault, cartLinesUpdateDefault, cartMetafieldDeleteDefault, cartMetafieldsSetDefault, cartNoteUpdateDefault, cartSelectedDeliveryOptionsUpdateDefault, cartSetIdDefault, createCartHandler, createStorefrontClient, createWithCache, generateCacheControlHeader, getPaginationVariables, getSelectedProductOptions, graphiqlLoader, isStorefrontApiError, storefrontRedirect };
2226
+ export { CacheCustom, CacheLong, CacheNone, CacheShort, CartForm, InMemoryCache, Pagination, Script, Seo, VariantSelector, cartAttributesUpdateDefault, cartBuyerIdentityUpdateDefault, cartCreateDefault, cartDiscountCodesUpdateDefault, cartGetDefault, cartGetIdDefault, cartLinesAddDefault, cartLinesRemoveDefault, cartLinesUpdateDefault, cartMetafieldDeleteDefault, cartMetafieldsSetDefault, cartNoteUpdateDefault, cartSelectedDeliveryOptionsUpdateDefault, cartSetIdDefault, createCartHandler, createContentSecurityPolicy, createStorefrontClient, createWithCache, generateCacheControlHeader, getPaginationVariables, getSelectedProductOptions, graphiqlLoader, isStorefrontApiError, storefrontRedirect, useNonce };
2154
2227
  //# sourceMappingURL=out.js.map
2155
2228
  //# sourceMappingURL=index.js.map