@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.
@@ -5,6 +5,11 @@ var serverRuntime = require('@remix-run/server-runtime');
5
5
  var react = require('react');
6
6
  var react$1 = require('@remix-run/react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
+ var cspBuilder = require('content-security-policy-builder');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var cspBuilder__default = /*#__PURE__*/_interopDefault(cspBuilder);
8
13
 
9
14
  var __defProp = Object.defineProperty;
10
15
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -422,7 +427,7 @@ var warnOnce = (string) => {
422
427
  };
423
428
 
424
429
  // src/version.ts
425
- var LIB_VERSION = "2023.7.3";
430
+ var LIB_VERSION = "2023.7.4";
426
431
 
427
432
  // src/storefront.ts
428
433
  var StorefrontApiError = class extends Error {
@@ -1337,7 +1342,7 @@ function Pagination({
1337
1342
  replace: true
1338
1343
  }) : null;
1339
1344
  },
1340
- [hasNextPage, nextPageUrl]
1345
+ [hasNextPage, nextPageUrl, state]
1341
1346
  );
1342
1347
  const PreviousLink = react.useMemo(
1343
1348
  () => function PrevLink(props) {
@@ -1349,7 +1354,7 @@ function Pagination({
1349
1354
  replace: true
1350
1355
  }) : null;
1351
1356
  },
1352
- [hasPreviousPage, previousPageUrl]
1357
+ [hasPreviousPage, previousPageUrl, state]
1353
1358
  );
1354
1359
  return children({
1355
1360
  state,
@@ -1368,42 +1373,41 @@ function usePagination(connection) {
1368
1373
  const params = new URLSearchParams(search);
1369
1374
  const direction = params.get("direction");
1370
1375
  const isPrevious = direction === "previous";
1371
- const nodes = react.useMemo(() => {
1372
- if (!state || !state?.nodes) {
1373
- return hydrogenReact.flattenConnection(connection);
1374
- }
1375
- if (isPrevious) {
1376
- return [...hydrogenReact.flattenConnection(connection), ...state.nodes];
1377
- } else {
1378
- return [...state.nodes, ...hydrogenReact.flattenConnection(connection)];
1379
- }
1380
- }, [state, connection]);
1381
- const currentPageInfo = react.useMemo(() => {
1382
- let pageStartCursor = state?.pageInfo?.startCursor === void 0 ? connection.pageInfo.startCursor : state.pageInfo.startCursor;
1383
- let pageEndCursor = state?.pageInfo?.endCursor === void 0 ? connection.pageInfo.endCursor : state.pageInfo.endCursor;
1376
+ const [nodes, setNodes] = react.useState(hydrogenReact.flattenConnection(connection));
1377
+ const [currentPageInfo, setCurrentPageInfo] = react.useState({
1378
+ startCursor: connection.pageInfo.startCursor,
1379
+ endCursor: connection.pageInfo.endCursor,
1380
+ hasPreviousPage: connection.pageInfo.hasPreviousPage,
1381
+ hasNextPage: connection.pageInfo.hasNextPage
1382
+ });
1383
+ react.useEffect(() => {
1384
1384
  if (state?.nodes) {
1385
- if (isPrevious) {
1386
- pageStartCursor = connection.pageInfo.startCursor;
1387
- } else {
1388
- pageEndCursor = connection.pageInfo.endCursor;
1385
+ setNodes(
1386
+ isPrevious ? [...hydrogenReact.flattenConnection(connection), ...state.nodes] : [...state.nodes, ...hydrogenReact.flattenConnection(connection)]
1387
+ );
1388
+ }
1389
+ if (state?.pageInfo) {
1390
+ let pageStartCursor = state?.pageInfo?.startCursor === void 0 ? connection.pageInfo.startCursor : state.pageInfo.startCursor;
1391
+ let pageEndCursor = state?.pageInfo?.endCursor === void 0 ? connection.pageInfo.endCursor : state.pageInfo.endCursor;
1392
+ let previousPageExists = state?.pageInfo?.hasPreviousPage === void 0 ? connection.pageInfo.hasPreviousPage : state.pageInfo.hasPreviousPage;
1393
+ let nextPageExists = state?.pageInfo?.hasNextPage === void 0 ? connection.pageInfo.hasNextPage : state.pageInfo.hasNextPage;
1394
+ if (state?.nodes) {
1395
+ if (isPrevious) {
1396
+ pageStartCursor = connection.pageInfo.startCursor;
1397
+ previousPageExists = connection.pageInfo.hasPreviousPage;
1398
+ } else {
1399
+ pageEndCursor = connection.pageInfo.endCursor;
1400
+ nextPageExists = connection.pageInfo.hasNextPage;
1401
+ }
1389
1402
  }
1403
+ setCurrentPageInfo({
1404
+ startCursor: pageStartCursor,
1405
+ endCursor: pageEndCursor,
1406
+ hasPreviousPage: previousPageExists,
1407
+ hasNextPage: nextPageExists
1408
+ });
1390
1409
  }
1391
- const previousPageExists = state?.pageInfo?.hasPreviousPage === void 0 ? connection.pageInfo.hasPreviousPage : state.pageInfo.hasPreviousPage;
1392
- const nextPageExists = state?.pageInfo?.hasNextPage === void 0 ? connection.pageInfo.hasNextPage : state.pageInfo.hasNextPage;
1393
- return {
1394
- startCursor: pageStartCursor,
1395
- endCursor: pageEndCursor,
1396
- hasPreviousPage: previousPageExists,
1397
- hasNextPage: nextPageExists
1398
- };
1399
- }, [
1400
- isPrevious,
1401
- state,
1402
- connection.pageInfo.hasNextPage,
1403
- connection.pageInfo.hasPreviousPage,
1404
- connection.pageInfo.startCursor,
1405
- connection.pageInfo.endCursor
1406
- ]);
1410
+ }, [state, connection]);
1407
1411
  const previousPageUrl = react.useMemo(() => {
1408
1412
  const params2 = new URLSearchParams(search);
1409
1413
  params2.set("direction", "previous");
@@ -2146,10 +2150,14 @@ function VariantSelector({
2146
2150
  handle,
2147
2151
  options = [],
2148
2152
  variants: _variants = [],
2153
+ productPath = "products",
2149
2154
  children
2150
2155
  }) {
2151
2156
  const variants = _variants instanceof Array ? _variants : hydrogenReact.flattenConnection(_variants);
2152
- const { searchParams, path, alreadyOnProductPage } = useVariantPath(handle);
2157
+ const { searchParams, path, alreadyOnProductPage } = useVariantPath(
2158
+ handle,
2159
+ productPath
2160
+ );
2153
2161
  const optionsWithOnlyOneValue = options.filter(
2154
2162
  (option) => option?.values?.length === 1
2155
2163
  );
@@ -2211,12 +2219,13 @@ var getSelectedProductOptions = (request) => {
2211
2219
  });
2212
2220
  return selectedOptions;
2213
2221
  };
2214
- function useVariantPath(handle) {
2222
+ function useVariantPath(handle, productPath) {
2215
2223
  const { pathname, search } = react$1.useLocation();
2216
2224
  return react.useMemo(() => {
2217
2225
  const match = /(\/[a-zA-Z]{2}-[a-zA-Z]{2}\/)/g.exec(pathname);
2218
2226
  const isLocalePathname = match && match.length > 0;
2219
- const path = isLocalePathname ? `${match[0]}products/${handle}` : `/products/${handle}`;
2227
+ productPath = productPath.startsWith("/") ? productPath.substring(1) : productPath;
2228
+ const path = isLocalePathname ? `${match[0]}${productPath}/${handle}` : `/${productPath}/${handle}`;
2220
2229
  const searchParams = new URLSearchParams(search);
2221
2230
  return {
2222
2231
  searchParams,
@@ -2226,8 +2235,76 @@ function useVariantPath(handle) {
2226
2235
  alreadyOnProductPage: path === pathname,
2227
2236
  path
2228
2237
  };
2229
- }, [pathname, search, handle]);
2238
+ }, [pathname, search, handle, productPath]);
2230
2239
  }
2240
+
2241
+ // src/csp/nonce.ts
2242
+ function generateNonce() {
2243
+ return toHexString(randomUint8Array());
2244
+ }
2245
+ function randomUint8Array() {
2246
+ try {
2247
+ return crypto.getRandomValues(new Uint8Array(16));
2248
+ } catch (e) {
2249
+ return new Uint8Array(16).map(() => Math.random() * 255 | 0);
2250
+ }
2251
+ }
2252
+ function toHexString(byteArray) {
2253
+ return Array.from(byteArray, function(byte) {
2254
+ return ("0" + (byte & 255).toString(16)).slice(-2);
2255
+ }).join("");
2256
+ }
2257
+
2258
+ // src/csp/csp.ts
2259
+ var NonceContext = react.createContext(void 0);
2260
+ var NonceProvider = NonceContext.Provider;
2261
+ var useNonce = () => react.useContext(NonceContext);
2262
+ function createContentSecurityPolicy(directives = {}) {
2263
+ const nonce = generateNonce();
2264
+ const header = createCSPHeader(nonce, directives);
2265
+ const Provider = ({ children }) => {
2266
+ return react.createElement(NonceProvider, { value: nonce }, children);
2267
+ };
2268
+ return {
2269
+ nonce,
2270
+ header,
2271
+ NonceProvider: Provider
2272
+ };
2273
+ }
2274
+ function createCSPHeader(nonce, directives = {}) {
2275
+ const nonceString = `'nonce-${nonce}'`;
2276
+ const defaultDirectives = {
2277
+ baseUri: ["'self'"],
2278
+ defaultSrc: [
2279
+ "'self'",
2280
+ nonceString,
2281
+ "https://cdn.shopify.com",
2282
+ // Used for the Customer Account API
2283
+ "https://shopify.com"
2284
+ ],
2285
+ frameAncestors: ["none"],
2286
+ styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.shopify.com"],
2287
+ connectSrc: ["'self'", "https://monorail-edge.shopifysvc.com"]
2288
+ };
2289
+ {
2290
+ defaultDirectives.connectSrc = ["*"];
2291
+ }
2292
+ const combinedDirectives = Object.assign({}, defaultDirectives, directives);
2293
+ if (combinedDirectives.scriptSrc instanceof Array && !combinedDirectives.scriptSrc.includes(nonceString)) {
2294
+ combinedDirectives.scriptSrc.push(nonceString);
2295
+ } else if (combinedDirectives.defaultSrc instanceof Array && !combinedDirectives.defaultSrc.includes(nonceString)) {
2296
+ combinedDirectives.defaultSrc.push(nonceString);
2297
+ }
2298
+ return cspBuilder__default.default({
2299
+ directives: combinedDirectives
2300
+ });
2301
+ }
2302
+ var Script = react.forwardRef(
2303
+ (props, ref) => {
2304
+ const nonce = useNonce();
2305
+ return /* @__PURE__ */ jsxRuntime.jsx("script", { ...props, nonce, ref });
2306
+ }
2307
+ );
2231
2308
  //! @see: https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate
2232
2309
  //! @see https://shopify.dev/docs/api/storefront/latest/queries/cart
2233
2310
  //! @see: https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd
@@ -2331,6 +2408,7 @@ exports.CacheShort = CacheShort;
2331
2408
  exports.CartForm = CartForm;
2332
2409
  exports.InMemoryCache = InMemoryCache;
2333
2410
  exports.Pagination = Pagination;
2411
+ exports.Script = Script;
2334
2412
  exports.Seo = Seo;
2335
2413
  exports.VariantSelector = VariantSelector;
2336
2414
  exports.cartAttributesUpdateDefault = cartAttributesUpdateDefault;
@@ -2348,6 +2426,7 @@ exports.cartNoteUpdateDefault = cartNoteUpdateDefault;
2348
2426
  exports.cartSelectedDeliveryOptionsUpdateDefault = cartSelectedDeliveryOptionsUpdateDefault;
2349
2427
  exports.cartSetIdDefault = cartSetIdDefault;
2350
2428
  exports.createCartHandler = createCartHandler;
2429
+ exports.createContentSecurityPolicy = createContentSecurityPolicy;
2351
2430
  exports.createStorefrontClient = createStorefrontClient;
2352
2431
  exports.createWithCache = createWithCache;
2353
2432
  exports.generateCacheControlHeader = generateCacheControlHeader;
@@ -2356,5 +2435,6 @@ exports.getSelectedProductOptions = getSelectedProductOptions;
2356
2435
  exports.graphiqlLoader = graphiqlLoader;
2357
2436
  exports.isStorefrontApiError = isStorefrontApiError;
2358
2437
  exports.storefrontRedirect = storefrontRedirect;
2438
+ exports.useNonce = useNonce;
2359
2439
  //# sourceMappingURL=out.js.map
2360
2440
  //# sourceMappingURL=index.cjs.map