@shopify/hydrogen 0.18.0 → 0.21.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.
Files changed (145) hide show
  1. package/CHANGELOG.md +200 -0
  2. package/config.d.ts +1 -0
  3. package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.d.ts +1 -1
  4. package/dist/esnext/components/CartLineImage/CartLineImage.client.d.ts +4 -7
  5. package/dist/esnext/components/CartLineImage/CartLineImage.client.js +1 -2
  6. package/dist/esnext/components/CartLinePrice/CartLinePrice.client.d.ts +1 -1
  7. package/dist/esnext/components/CartProvider/CartProvider.client.d.ts +3 -1
  8. package/dist/esnext/components/CartProvider/CartProvider.client.js +22 -20
  9. package/dist/esnext/components/CartProvider/cart-queries.d.ts +10 -9
  10. package/dist/esnext/components/CartProvider/cart-queries.js +58 -743
  11. package/dist/esnext/components/CartProvider/hooks.client.js +4 -2
  12. package/dist/esnext/components/CartProvider/types.d.ts +2 -0
  13. package/dist/esnext/components/Image/Image.d.ts +78 -34
  14. package/dist/esnext/components/Image/Image.js +54 -51
  15. package/dist/esnext/components/Image/index.d.ts +1 -0
  16. package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +2 -15
  17. package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -1
  18. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +2 -6
  19. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +10 -4
  20. package/dist/esnext/components/MediaFile/MediaFile.d.ts +2 -2
  21. package/dist/esnext/components/MediaFile/MediaFile.js +2 -2
  22. package/dist/esnext/components/Money/Money.client.d.ts +11 -5
  23. package/dist/esnext/components/Money/Money.client.js +16 -3
  24. package/dist/esnext/components/ProductPrice/ProductPrice.client.d.ts +1 -2
  25. package/dist/esnext/components/ProductPrice/ProductPrice.client.js +1 -2
  26. package/dist/esnext/components/Video/Video.d.ts +3 -3
  27. package/dist/esnext/components/Video/Video.js +7 -4
  28. package/dist/esnext/components/index.d.ts +0 -3
  29. package/dist/esnext/components/index.js +0 -3
  30. package/dist/esnext/entry-server.d.ts +13 -1
  31. package/dist/esnext/entry-server.js +18 -51
  32. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +18 -3
  33. package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.js +2 -0
  34. package/dist/esnext/foundation/fetchSync/server/fetchSync.d.ts +1 -1
  35. package/dist/esnext/foundation/fetchSync/server/fetchSync.js +1 -1
  36. package/dist/esnext/foundation/useQuery/hooks.js +8 -9
  37. package/dist/esnext/foundation/useSession/useSession.d.ts +1 -1
  38. package/dist/esnext/foundation/useSession/useSession.js +1 -1
  39. package/dist/esnext/framework/Hydration/Html.js +3 -1
  40. package/dist/esnext/framework/Hydration/ServerComponentResponse.server.d.ts +1 -1
  41. package/dist/esnext/framework/Hydration/ServerComponentResponse.server.js +2 -1
  42. package/dist/esnext/framework/Hydration/rsc.d.ts +0 -3
  43. package/dist/esnext/framework/Hydration/rsc.js +40 -12
  44. package/dist/esnext/framework/cache/in-memory.js +0 -6
  45. package/dist/esnext/framework/cache-sub-request.d.ts +17 -0
  46. package/dist/esnext/framework/cache-sub-request.js +64 -0
  47. package/dist/esnext/framework/cache.d.ts +6 -6
  48. package/dist/esnext/framework/cache.js +36 -33
  49. package/dist/esnext/framework/plugin.js +5 -30
  50. package/dist/esnext/framework/plugins/vite-plugin-client-imports.d.ts +2 -0
  51. package/dist/esnext/framework/plugins/vite-plugin-client-imports.js +25 -0
  52. package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.d.ts +1 -1
  53. package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.js +73 -3
  54. package/dist/esnext/framework/plugins/vite-plugin-hydration-auto-import.js +1 -4
  55. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +6 -4
  56. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +1 -1
  57. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +2 -3
  58. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +1 -0
  59. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.js +35 -0
  60. package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +1 -1
  61. package/dist/esnext/framework/plugins/vite-plugin-ssr-interop.js +6 -3
  62. package/dist/esnext/hooks/useCountry/useCountry.d.ts +1 -11
  63. package/dist/esnext/hooks/useCountry/useCountry.js +1 -1
  64. package/dist/esnext/index.d.ts +4 -0
  65. package/dist/esnext/index.js +4 -0
  66. package/dist/esnext/node.d.ts +1 -0
  67. package/dist/esnext/node.js +1 -0
  68. package/dist/esnext/storefront-api-types.d.ts +5 -3
  69. package/dist/esnext/storefront-api-types.js +5 -3
  70. package/dist/esnext/types.d.ts +4 -3
  71. package/dist/esnext/utilities/bot-ua.js +4 -0
  72. package/dist/esnext/utilities/html-encoding.d.ts +2 -0
  73. package/dist/esnext/utilities/html-encoding.js +16 -0
  74. package/dist/esnext/utilities/image_size.d.ts +4 -22
  75. package/dist/esnext/utilities/image_size.js +15 -33
  76. package/dist/esnext/utilities/index.d.ts +2 -1
  77. package/dist/esnext/utilities/index.js +2 -1
  78. package/dist/esnext/utilities/log/log-cache-api-status.js +5 -1
  79. package/dist/esnext/version.d.ts +1 -1
  80. package/dist/esnext/version.js +1 -1
  81. package/dist/node/components/Image/Image.d.ts +84 -0
  82. package/dist/node/components/Image/Image.js +86 -0
  83. package/dist/node/components/Image/index.d.ts +2 -0
  84. package/dist/node/components/Image/index.js +5 -0
  85. package/dist/node/entry-server.d.ts +13 -1
  86. package/dist/node/entry-server.js +18 -51
  87. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +18 -3
  88. package/dist/node/framework/Hydration/Html.js +3 -1
  89. package/dist/node/framework/Hydration/ServerComponentResponse.server.d.ts +1 -1
  90. package/dist/node/framework/Hydration/ServerComponentResponse.server.js +2 -1
  91. package/dist/node/framework/Hydration/rsc.d.ts +0 -3
  92. package/dist/node/framework/Hydration/rsc.js +40 -12
  93. package/dist/node/framework/cache/in-memory.js +0 -6
  94. package/dist/node/framework/cache-sub-request.d.ts +17 -0
  95. package/dist/node/framework/cache-sub-request.js +95 -0
  96. package/dist/node/framework/cache.d.ts +6 -6
  97. package/dist/node/framework/cache.js +38 -35
  98. package/dist/node/framework/plugin.js +5 -53
  99. package/dist/node/framework/plugins/vite-plugin-client-imports.d.ts +2 -0
  100. package/dist/node/framework/plugins/vite-plugin-client-imports.js +28 -0
  101. package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.d.ts +1 -1
  102. package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.js +76 -3
  103. package/dist/node/framework/plugins/vite-plugin-hydration-auto-import.js +1 -4
  104. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +6 -4
  105. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +1 -1
  106. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +2 -3
  107. package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +1 -0
  108. package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.js +41 -0
  109. package/dist/node/framework/plugins/vite-plugin-platform-entry.js +1 -1
  110. package/dist/node/framework/plugins/vite-plugin-ssr-interop.js +6 -3
  111. package/dist/node/storefront-api-types.d.ts +5 -3
  112. package/dist/node/storefront-api-types.js +5 -3
  113. package/dist/node/types.d.ts +4 -3
  114. package/dist/node/utilities/bot-ua.js +4 -0
  115. package/dist/node/utilities/html-encoding.d.ts +2 -0
  116. package/dist/node/utilities/html-encoding.js +21 -0
  117. package/dist/node/utilities/image_size.d.ts +4 -22
  118. package/dist/node/utilities/image_size.js +16 -58
  119. package/dist/node/utilities/index.d.ts +2 -1
  120. package/dist/node/utilities/index.js +4 -2
  121. package/dist/node/utilities/log/log-cache-api-status.js +5 -1
  122. package/dist/node/version.d.ts +1 -1
  123. package/dist/node/version.js +1 -1
  124. package/entry-server.d.ts +1 -1
  125. package/package.json +3 -3
  126. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +200 -31
  127. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-client-proxy.js +2 -0
  128. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +200 -31
  129. package/vendor/react-server-dom-vite/package.json +2 -1
  130. package/dist/esnext/components/ProductDescription/ProductDescription.client.d.ts +0 -13
  131. package/dist/esnext/components/ProductDescription/ProductDescription.client.js +0 -16
  132. package/dist/esnext/components/ProductDescription/index.d.ts +0 -1
  133. package/dist/esnext/components/ProductDescription/index.js +0 -1
  134. package/dist/esnext/components/ProductMetafield/ProductMetafield.client.d.ts +0 -21
  135. package/dist/esnext/components/ProductMetafield/ProductMetafield.client.js +0 -42
  136. package/dist/esnext/components/ProductMetafield/index.d.ts +0 -2
  137. package/dist/esnext/components/ProductMetafield/index.js +0 -1
  138. package/dist/esnext/components/ProductTitle/ProductTitle.client.d.ts +0 -13
  139. package/dist/esnext/components/ProductTitle/ProductTitle.client.js +0 -16
  140. package/dist/esnext/components/ProductTitle/index.d.ts +0 -1
  141. package/dist/esnext/components/ProductTitle/index.js +0 -1
  142. package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +0 -15
  143. package/dist/esnext/components/UnitPrice/UnitPrice.client.js +0 -22
  144. package/dist/esnext/components/UnitPrice/index.d.ts +0 -1
  145. package/dist/esnext/components/UnitPrice/index.js +0 -1
@@ -1,4 +1,4 @@
1
- export { addImageSizeParametersToUrl, useImageUrl, getShopifyImageDimensions, shopifyImageLoader, } from './image_size';
1
+ export { addImageSizeParametersToUrl, getShopifyImageDimensions, shopifyImageLoader, } from './image_size';
2
2
  export { addParametersToEmbeddedVideoUrl, useEmbeddedVideoUrl, } from './video_parameters';
3
3
  export { loadScript } from './load_script';
4
4
  export { wrapPromise } from './suspense';
@@ -9,3 +9,4 @@ export { getMeasurementAsParts, getMeasurementAsString } from './measurement';
9
9
  export { parseMetafieldValue } from './parseMetafieldValue';
10
10
  export { fetchBuilder, graphqlRequestBody, decodeShopifyId } from './fetch';
11
11
  export { getTime } from './timing';
12
+ export { htmlEncode, htmlDecode } from './html-encoding';
@@ -5,5 +5,9 @@ export function logCacheApiStatus(status, url) {
5
5
  if (!log.options().showCacheApiStatus) {
6
6
  return;
7
7
  }
8
- log.debug(gray(`[Cache] ${status === null || status === void 0 ? void 0 : status.padEnd(8)} query ${findQueryName(url)}`));
8
+ let queryName;
9
+ if (/shopify\.dev/.test(url)) {
10
+ queryName = findQueryName(url);
11
+ }
12
+ log.debug(gray(`[Cache] ${status === null || status === void 0 ? void 0 : status.padEnd(8)} ${queryName ? `query ${queryName}` : decodeURIComponent(url)}`));
9
13
  }
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "0.18.0";
1
+ export declare const LIB_VERSION = "0.21.0";
@@ -1 +1 @@
1
- export const LIB_VERSION = '0.18.0';
1
+ export const LIB_VERSION = '0.21.0';
@@ -0,0 +1,84 @@
1
+ import * as React from 'react';
2
+ import type { Image as ImageType } from '../../storefront-api-types';
3
+ import type { PartialDeep, Simplify, SetRequired } from 'type-fest';
4
+ declare type HtmlImageProps = React.ImgHTMLAttributes<HTMLImageElement>;
5
+ declare type ImageProps<GenericLoaderOpts> = Simplify<ShopifyImageProps | ExternalImageProps<GenericLoaderOpts>>;
6
+ export declare function Image<GenericLoaderOpts>(props: ImageProps<GenericLoaderOpts>): JSX.Element;
7
+ export declare type ShopifyLoaderOptions = {
8
+ crop?: 'top' | 'bottom' | 'left' | 'right' | 'center';
9
+ scale?: 2 | 3;
10
+ width?: HtmlImageProps['width'] | ImageType['width'];
11
+ height?: HtmlImageProps['height'] | ImageType['height'];
12
+ };
13
+ export declare type ShopifyLoaderParams = Simplify<ShopifyLoaderOptions & {
14
+ src: ImageType['url'];
15
+ }>;
16
+ export declare type ShopifyImageProps = Omit<HtmlImageProps, 'src'> & {
17
+ /** An object with fields that correspond to the Storefront API's
18
+ * [Image object](https://shopify.dev/api/storefront/reference/common-objects/image).
19
+ * The `data` prop is required if `src` isn't used, but both props shouldn't be used
20
+ * at the same time. If both `src` and `data` are passed, then `data` takes priority.
21
+ */
22
+ data: PartialDeep<ImageType>;
23
+ /** A custom function that generates the image URL. Parameters passed in
24
+ * are either `ShopifyLoaderParams` if using the `data` prop, or the
25
+ * `LoaderOptions` object that you pass to `loaderOptions`.
26
+ */
27
+ loader?: (params: ShopifyLoaderParams) => string;
28
+ /** An object of `loader` function options. For example, if the `loader` function
29
+ * requires a `scale` option, then the value can be a property of the
30
+ * `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
31
+ * is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
32
+ * prop is used, the data shape is whatever you define it to be, and this shape
33
+ * will be passed to `loader`.
34
+ */
35
+ loaderOptions?: ShopifyLoaderOptions;
36
+ /**
37
+ * 'src' shouldn't be passed when 'data' is used.
38
+ */
39
+ src?: never;
40
+ };
41
+ declare type LoaderProps<GenericLoaderOpts> = {
42
+ /** A URL string. This string can be an absolute path or a relative path depending
43
+ * on the `loader`. The `src` prop is required if `data` isn't used, but both
44
+ * props shouldn't be used at the same time. If both `src` and `data` are passed,
45
+ * then `data` takes priority.
46
+ */
47
+ src: HtmlImageProps['src'];
48
+ /** The integer or string value for the width of the image. This is a required prop
49
+ * when `src` is present.
50
+ */
51
+ width: HtmlImageProps['width'];
52
+ /** The integer or string value for the height of the image. This is a required prop
53
+ * when `src` is present.
54
+ */
55
+ height: HtmlImageProps['height'];
56
+ /** An object of `loader` function options. For example, if the `loader` function
57
+ * requires a `scale` option, then the value can be a property of the
58
+ * `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
59
+ * is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
60
+ * prop is used, the data shape is whatever you define it to be, and this shape
61
+ * will be passed to `loader`.
62
+ */
63
+ loaderOptions?: GenericLoaderOpts;
64
+ };
65
+ declare type ExternalImageProps<GenericLoaderOpts> = SetRequired<HtmlImageProps, 'src' | 'width' | 'height'> & {
66
+ /** A custom function that generates the image URL. Parameters passed in
67
+ * are either `ShopifyLoaderParams` if using the `data` prop, or the
68
+ * `LoaderOptions` object that you pass to `loaderOptions`.
69
+ */
70
+ loader?: (params: LoaderProps<GenericLoaderOpts>) => string;
71
+ /** An object of `loader` function options. For example, if the `loader` function
72
+ * requires a `scale` option, then the value can be a property of the
73
+ * `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
74
+ * is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
75
+ * prop is used, the data shape is whatever you define it to be, and this shape
76
+ * will be passed to `loader`.
77
+ */
78
+ loaderOptions?: GenericLoaderOpts;
79
+ /**
80
+ * 'data' shouldn't be passed when 'src' is used.
81
+ */
82
+ data?: never;
83
+ };
84
+ export {};
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.Image = void 0;
27
+ const React = __importStar(require("react"));
28
+ const utilities_1 = require("../../utilities");
29
+ function Image(props) {
30
+ if (!props.data && !props.src) {
31
+ throw new Error(`<Image/>: requires either a 'data' or 'src' prop.`);
32
+ }
33
+ if (props.data && props.src) {
34
+ console.warn(`<Image/>: using both 'data' and 'src' props is not supported; using the 'data' prop by default`);
35
+ }
36
+ if (props.data) {
37
+ return React.createElement(ShopifyImage, { ...props });
38
+ }
39
+ else {
40
+ return React.createElement(ExternalImage, { ...props });
41
+ }
42
+ }
43
+ exports.Image = Image;
44
+ function ShopifyImage({ data, width, height, loading, loader = utilities_1.shopifyImageLoader, loaderOptions, ...rest }) {
45
+ var _a, _b, _c;
46
+ if (!data.url) {
47
+ throw new Error(`<Image/>: the 'data' prop requires the 'url' property`);
48
+ }
49
+ if (!data.altText && !rest.alt) {
50
+ console.warn(`<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. ${data.id ? `Image ID: ${data.id}` : ''}`);
51
+ }
52
+ const { width: finalWidth, height: finalHeight } = (0, utilities_1.getShopifyImageDimensions)(data, loaderOptions);
53
+ if (!finalWidth || !finalHeight) {
54
+ console.warn(`<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties`);
55
+ }
56
+ let finalSrc = data.url;
57
+ if (loader) {
58
+ finalSrc = loader({
59
+ ...loaderOptions,
60
+ src: data.url,
61
+ width: finalWidth,
62
+ height: finalHeight,
63
+ });
64
+ }
65
+ /* eslint-disable hydrogen/prefer-image-component */
66
+ return (React.createElement("img", { id: (_a = data.id) !== null && _a !== void 0 ? _a : '', alt: (_c = (_b = data.altText) !== null && _b !== void 0 ? _b : rest.alt) !== null && _c !== void 0 ? _c : '', loading: loading !== null && loading !== void 0 ? loading : 'lazy', ...rest, src: finalSrc, width: finalWidth !== null && finalWidth !== void 0 ? finalWidth : undefined, height: finalHeight !== null && finalHeight !== void 0 ? finalHeight : undefined }));
67
+ /* eslint-enable hydrogen/prefer-image-component */
68
+ }
69
+ function ExternalImage({ src, width, height, alt, loader, loaderOptions, loading, ...rest }) {
70
+ if (!width || !height) {
71
+ throw new Error(`<Image/>: when 'src' is provided, 'width' and 'height' are required and need to be valid values (i.e. greater than zero). Provided values: 'src': ${src}, 'width': ${width}, 'height': ${height}`);
72
+ }
73
+ if (!alt) {
74
+ console.warn(`<Image/>: when 'src' is provided, 'alt' should also be provided`);
75
+ }
76
+ let finalSrc = src;
77
+ if (loader) {
78
+ finalSrc = loader({ src, width, height, ...loaderOptions });
79
+ if (typeof finalSrc !== 'string' || !finalSrc) {
80
+ throw new Error(`<Image/>: 'loader' did not return a valid string`);
81
+ }
82
+ }
83
+ /* eslint-disable hydrogen/prefer-image-component */
84
+ return (React.createElement("img", { ...rest, src: finalSrc, width: width, height: height, alt: alt !== null && alt !== void 0 ? alt : '', loading: loading !== null && loading !== void 0 ? loading : 'lazy' }));
85
+ /* eslint-enable hydrogen/prefer-image-component */
86
+ }
@@ -0,0 +1,2 @@
1
+ export { Image } from './Image';
2
+ export type { ShopifyLoaderParams, ShopifyLoaderOptions, ShopifyImageProps, } from './Image';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Image = void 0;
4
+ var Image_1 = require("./Image");
5
+ Object.defineProperty(exports, "Image", { enumerable: true, get: function () { return Image_1.Image; } });
@@ -1,5 +1,8 @@
1
1
  /// <reference types="node" />
2
- import type { HydrogenConfig } from './types';
2
+ import { Logger } from './utilities/log';
3
+ import type { HydrogenConfig, ImportGlobEagerOutput } from './types';
4
+ import { ServerComponentResponse } from './framework/Hydration/ServerComponentResponse.server';
5
+ import { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
3
6
  import type { ServerResponse, IncomingMessage } from 'http';
4
7
  import { RuntimeContext } from './framework/runtime';
5
8
  declare global {
@@ -20,4 +23,13 @@ export interface RequestHandler {
20
23
  (request: Request | IncomingMessage, options: RequestHandlerOptions): Promise<Response | undefined>;
21
24
  }
22
25
  export declare const renderHydrogen: (App: any, hydrogenConfig?: HydrogenConfig | undefined) => RequestHandler;
26
+ declare type SharedServerProps = {
27
+ state?: object | null;
28
+ request: ServerComponentRequest;
29
+ response: ServerComponentResponse;
30
+ log: Logger;
31
+ };
32
+ export declare type AppProps = SharedServerProps & {
33
+ routes?: ImportGlobEagerOutput;
34
+ };
23
35
  export default renderHydrogen;
@@ -44,6 +44,7 @@ const Analytics_server_1 = require("./foundation/Analytics/Analytics.server");
44
44
  const ServerAnalyticsRoute_server_1 = require("./foundation/Analytics/ServerAnalyticsRoute.server");
45
45
  const session_1 = require("./foundation/session/session");
46
46
  const parse_1 = require("./utilities/parse");
47
+ const utilities_1 = require("./utilities");
47
48
  const DOCTYPE = '<!DOCTYPE html>';
48
49
  const CONTENT_TYPE = 'Content-Type';
49
50
  const HTML_CONTENT_TYPE = 'text/html; charset=UTF-8';
@@ -89,7 +90,10 @@ const renderHydrogen = (App, hydrogenConfig) => {
89
90
  : apiResponse;
90
91
  }
91
92
  }
92
- const isStreamable = !(0, bot_ua_1.isBotUA)(url, request.headers.get('user-agent')) &&
93
+ const isStreamable = (hydrogenConfig.enableStreaming
94
+ ? hydrogenConfig.enableStreaming(request)
95
+ : true) &&
96
+ !(0, bot_ua_1.isBotUA)(url, request.headers.get('user-agent')) &&
93
97
  (!!streamableResponse || (await (0, streaming_server_1.isStreamingSupported)()));
94
98
  let template = typeof indexTemplate === 'function'
95
99
  ? await indexTemplate(url.toString())
@@ -169,11 +173,7 @@ async function render(url, { App, request, template, componentResponse, nonce, l
169
173
  headers.set(CONTENT_TYPE, HTML_CONTENT_TYPE);
170
174
  html = (0, Html_1.applyHtmlHead)(html, request.ctx.head, template);
171
175
  if (flight) {
172
- html = html.replace('</body>', () => `${flightContainer({
173
- init: true,
174
- nonce,
175
- chunk: flight,
176
- })}</body>`);
176
+ html = html.replace('</body>', () => flightContainer(flight) + '</body>');
177
177
  }
178
178
  postRequestTasks('ssr', status, request, componentResponse);
179
179
  return new Response(html, {
@@ -201,12 +201,10 @@ async function stream(url, { App, request, response, componentResponse, template
201
201
  const rscToScriptTagReadable = new ReadableStream({
202
202
  start(controller) {
203
203
  log.trace('rsc start chunks');
204
- let init = true;
205
204
  const encoder = new TextEncoder();
206
205
  (0, streaming_server_1.bufferReadableStream)(rscReadable.getReader(), (chunk) => {
207
- const scriptTag = flightContainer({ init, chunk, nonce });
208
- controller.enqueue(encoder.encode(scriptTag));
209
- init = false;
206
+ const metaTag = flightContainer(chunk);
207
+ controller.enqueue(encoder.encode(metaTag));
210
208
  }).then(() => {
211
209
  log.trace('rsc finish chunks');
212
210
  return controller.close();
@@ -397,34 +395,15 @@ async function hydrate(url, { App, log, request, response, isStreamable, compone
397
395
  request,
398
396
  response: componentResponse,
399
397
  });
400
- if (__WORKER__) {
401
- const rscReadable = (0, streaming_server_1.rscRenderToReadableStream)(AppRSC);
402
- if (isStreamable && (await (0, streaming_server_1.isStreamingSupported)())) {
403
- postRequestTasks('rsc', 200, request, componentResponse);
404
- return new Response(rscReadable);
405
- }
406
- // Note: CFW does not support reader.piteTo nor iterable syntax
407
- const bufferedBody = await (0, streaming_server_1.bufferReadableStream)(rscReadable.getReader());
408
- postRequestTasks('rsc', 200, request, componentResponse);
409
- return new Response(bufferedBody, {
410
- headers: {
411
- 'cache-control': componentResponse.cacheControlHeader,
412
- },
413
- });
414
- }
415
- else if (response) {
416
- const rscWriter = await Promise.resolve().then(() => __importStar(require(
417
- // @ts-ignore
418
- '@shopify/hydrogen/vendor/react-server-dom-vite/writer.node.server')));
419
- const streamer = rscWriter.renderToPipeableStream(AppRSC);
420
- response.writeHead(200, 'ok', {
398
+ const rscReadable = (0, streaming_server_1.rscRenderToReadableStream)(AppRSC);
399
+ // Note: CFW does not support reader.piteTo nor iterable syntax
400
+ const bufferedBody = await (0, streaming_server_1.bufferReadableStream)(rscReadable.getReader());
401
+ postRequestTasks('rsc', 200, request, componentResponse);
402
+ return new Response(bufferedBody, {
403
+ headers: {
421
404
  'cache-control': componentResponse.cacheControlHeader,
422
- });
423
- const stream = streamer.pipe(response);
424
- stream.on('finish', function () {
425
- postRequestTasks('rsc', response.statusCode, request, componentResponse);
426
- });
427
- }
405
+ },
406
+ });
428
407
  }
429
408
  function buildAppRSC({ App, log, state, request, response }) {
430
409
  const hydrogenServerProps = { request, response, log };
@@ -555,20 +534,8 @@ async function createNodeWriter() {
555
534
  const { PassThrough } = await Promise.resolve().then(() => __importStar(require(streamImport)));
556
535
  return new PassThrough();
557
536
  }
558
- function flightContainer({ init, chunk, nonce, }) {
559
- let script = `<script${nonce ? ` nonce="${nonce}"` : ''}>`;
560
- if (init) {
561
- script += 'var __flight=[];';
562
- }
563
- if (chunk) {
564
- const normalizedChunk = chunk
565
- // 1. Duplicate the escape char (\) for already escaped characters (e.g. \n or \").
566
- .replace(/\\/g, String.raw `\\`)
567
- // 2. Escape existing backticks to allow wrapping the whole thing in `...`.
568
- .replace(/`/g, String.raw `\``);
569
- script += `__flight.push(\`${normalizedChunk}\`)`;
570
- }
571
- return script + '</script>';
537
+ function flightContainer(chunk) {
538
+ return `<meta data-flight="${(0, utilities_1.htmlEncode)(chunk)}" />`;
572
539
  }
573
540
  function postRequestTasks(type, status, request, componentResponse) {
574
541
  (0, log_1.logServerResponse)(type, request, status);
@@ -35,12 +35,27 @@ function requestCacheRSC() {
35
35
  return new Map();
36
36
  }
37
37
  requestCacheRSC.key = Symbol.for('HYDROGEN_REQUEST');
38
+ // Note: use this only during RSC/Flight rendering. The React dispatcher
39
+ // for SSR/Fizz rendering does not implement getCacheForType.
40
+ function getCacheForType(resource) {
41
+ var _a;
42
+ const dispatcher =
43
+ // @ts-ignore
44
+ react_1.default.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
45
+ .ReactCurrentDispatcher.current;
46
+ // @ts-ignore
47
+ if (__DEV__ && typeof jest !== 'undefined' && !dispatcher.getCacheForType) {
48
+ // Jest does not have access to the RSC runtime, mock it here:
49
+ // @ts-ignore
50
+ return ((_a = globalThis.__jestRscCache) !== null && _a !== void 0 ? _a : (globalThis.__jestRscCache = resource()));
51
+ }
52
+ return dispatcher.getCacheForType(resource);
53
+ }
38
54
  function ServerRequestProvider({ isRSC, request, children, }) {
39
55
  if (isRSC) {
40
56
  // Save the request object in a React cache that is
41
57
  // scoped to this current rendering.
42
- // @ts-ignore
43
- const requestCache = react_1.default.unstable_getCacheForType(requestCacheRSC);
58
+ const requestCache = getCacheForType(requestCacheRSC);
44
59
  requestCache.set(requestCacheRSC.key, request);
45
60
  return children;
46
61
  }
@@ -54,7 +69,7 @@ function useServerRequest() {
54
69
  try {
55
70
  // This cache only works during RSC rendering:
56
71
  // @ts-ignore
57
- const cache = react_1.default.unstable_getCacheForType(requestCacheRSC);
72
+ const cache = getCacheForType(requestCacheRSC);
58
73
  request = cache ? cache.get(requestCacheRSC.key) : null;
59
74
  }
60
75
  catch (_a) {
@@ -33,7 +33,9 @@ function Html({ children, template, htmlAttrs, bodyAttrs }) {
33
33
  if (import.meta.env.DEV) {
34
34
  // Fix React Refresh for async scripts.
35
35
  // https://github.com/vitejs/vite/issues/6759
36
- head = head.replace(/>(\s*?import[\s\w]+?['"]\/@react-refresh)/, ' async="">$1');
36
+ head =
37
+ '<script></script>' + // Fix for Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1737882
38
+ head.replace(/>(\s*?import[\s\w]+?['"]\/@react-refresh)/, ' async="">$1');
37
39
  }
38
40
  return (react_1.default.createElement("html", { ...attrsToProps(getHtmlAttrs(template)), ...htmlAttrs },
39
41
  react_1.default.createElement("head", { dangerouslySetInnerHTML: { __html: head } }),
@@ -2,7 +2,7 @@ import type { CachingStrategy } from '../../types';
2
2
  import React from 'react';
3
3
  export declare class ServerComponentResponse extends Response {
4
4
  private wait;
5
- private cacheOptions?;
5
+ private cacheOptions;
6
6
  customStatus?: {
7
7
  code?: number;
8
8
  text?: string;
@@ -12,6 +12,7 @@ class ServerComponentResponse extends Response {
12
12
  constructor() {
13
13
  super(...arguments);
14
14
  this.wait = false;
15
+ this.cacheOptions = (0, CachingStrategy_1.CacheSeconds)();
15
16
  /**
16
17
  * Allow custom body to be a string or a Promise.
17
18
  */
@@ -31,7 +32,7 @@ class ServerComponentResponse extends Response {
31
32
  this.cacheOptions = options;
32
33
  }
33
34
  get cacheControlHeader() {
34
- return (0, CachingStrategy_1.generateCacheControlHeader)(this.cacheOptions || (0, CachingStrategy_1.CacheSeconds)());
35
+ return (0, CachingStrategy_1.generateCacheControlHeader)(this.cacheOptions);
35
36
  }
36
37
  writeHead({ status, statusText, headers, } = {}) {
37
38
  if (status || statusText) {
@@ -1,6 +1,3 @@
1
- declare global {
2
- var __flight: Array<string>;
3
- }
4
1
  /**
5
2
  * Much of this is borrowed from React's demo implementation:
6
3
  * @see https://github.com/reactjs/server-components-demo/blob/main/src/Cache.client.js
@@ -3,12 +3,41 @@
3
3
  // so it is considered ESM instead of CJS?
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.useRefresh = exports.useServerResponse = void 0;
6
- // @ts-ignore
7
- const react_1 = require("react");
8
6
  const react_server_dom_vite_1 = require("@shopify/hydrogen/vendor/react-server-dom-vite");
9
7
  const constants_1 = require("../../constants");
8
+ const utilities_1 = require("../../utilities");
10
9
  let rscReader;
11
- if (globalThis.__flight && __flight.length > 0) {
10
+ // Hydrate an SSR response from <meta> tags placed in the DOM.
11
+ const flightChunks = [];
12
+ const FLIGHT_ATTRIBUTE = 'data-flight';
13
+ function addElementToFlightChunks(el) {
14
+ const chunk = el.getAttribute(FLIGHT_ATTRIBUTE);
15
+ if (chunk) {
16
+ flightChunks.push((0, utilities_1.htmlDecode)(chunk));
17
+ }
18
+ }
19
+ // Get initial payload
20
+ document
21
+ .querySelectorAll('[' + FLIGHT_ATTRIBUTE + ']')
22
+ .forEach(addElementToFlightChunks);
23
+ // Create a mutation observer on the document to detect when new
24
+ // <meta data-flight> tags are added, and add them to the array.
25
+ const observer = new MutationObserver((mutations) => {
26
+ mutations.forEach((mutation) => {
27
+ mutation.addedNodes.forEach((node) => {
28
+ if (node instanceof HTMLElement &&
29
+ node.tagName === 'META' &&
30
+ node.hasAttribute(FLIGHT_ATTRIBUTE)) {
31
+ addElementToFlightChunks(node);
32
+ }
33
+ });
34
+ });
35
+ });
36
+ observer.observe(document.documentElement, {
37
+ childList: true,
38
+ subtree: true,
39
+ });
40
+ if (flightChunks.length > 0) {
12
41
  const contentLoaded = new Promise((resolve) => document.addEventListener('DOMContentLoaded', resolve));
13
42
  try {
14
43
  rscReader = new ReadableStream({
@@ -18,9 +47,12 @@ if (globalThis.__flight && __flight.length > 0) {
18
47
  controller.enqueue(encoder.encode(chunk));
19
48
  return 0;
20
49
  };
21
- __flight.forEach(write);
22
- __flight.push = write;
23
- contentLoaded.then(() => controller.close());
50
+ flightChunks.forEach(write);
51
+ flightChunks.push = write;
52
+ contentLoaded.then(() => {
53
+ controller.close();
54
+ observer.disconnect();
55
+ });
24
56
  },
25
57
  });
26
58
  }
@@ -28,9 +60,7 @@ if (globalThis.__flight && __flight.length > 0) {
28
60
  // Old browser, will try a new hydration request later
29
61
  }
30
62
  }
31
- function createResponseCache() {
32
- return new Map();
33
- }
63
+ const cache = new Map();
34
64
  /**
35
65
  * Much of this is borrowed from React's demo implementation:
36
66
  * @see https://github.com/reactjs/server-components-demo/blob/main/src/Cache.client.js
@@ -39,7 +69,6 @@ function createResponseCache() {
39
69
  */
40
70
  function useServerResponse(state) {
41
71
  const key = JSON.stringify(state);
42
- const cache = (0, react_1.unstable_getCacheForType)(createResponseCache);
43
72
  let response = cache.get(key);
44
73
  if (response) {
45
74
  return response;
@@ -69,7 +98,6 @@ function useServerResponse(state) {
69
98
  }
70
99
  exports.useServerResponse = useServerResponse;
71
100
  function useRefresh() {
72
- const refreshCache = (0, react_1.unstable_useCacheRefresh)();
73
- refreshCache();
101
+ cache.clear();
74
102
  }
75
103
  exports.useRefresh = useRefresh;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InMemoryCache = void 0;
4
- const log_1 = require("../../utilities/log");
5
4
  /**
6
5
  * This is an in-memory implementation of `Cache` that *barely*
7
6
  * works and is only meant to be used during development.
@@ -11,7 +10,6 @@ class InMemoryCache {
11
10
  this.store = new Map();
12
11
  }
13
12
  put(request, response) {
14
- (0, log_1.logCacheApiStatus)('PUT-dev', request.url);
15
13
  this.store.set(request.url, {
16
14
  value: response,
17
15
  date: new Date(),
@@ -21,7 +19,6 @@ class InMemoryCache {
21
19
  var _a, _b;
22
20
  const match = this.store.get(request.url);
23
21
  if (!match) {
24
- (0, log_1.logCacheApiStatus)('MISS-dev', request.url);
25
22
  return;
26
23
  }
27
24
  const { value, date } = match;
@@ -31,7 +28,6 @@ class InMemoryCache {
31
28
  const age = (new Date().valueOf() - date.valueOf()) / 1000;
32
29
  const isMiss = age > maxAge + swr;
33
30
  if (isMiss) {
34
- (0, log_1.logCacheApiStatus)('MISS-dev', request.url);
35
31
  this.store.delete(request.url);
36
32
  return;
37
33
  }
@@ -39,7 +35,6 @@ class InMemoryCache {
39
35
  const headers = new Headers(value.headers);
40
36
  headers.set('cache', isStale ? 'STALE' : 'HIT');
41
37
  headers.set('date', date.toUTCString());
42
- (0, log_1.logCacheApiStatus)(`${headers.get('cache')}-dev`, request.url);
43
38
  const response = new Response(value.body, {
44
39
  headers,
45
40
  });
@@ -47,7 +42,6 @@ class InMemoryCache {
47
42
  }
48
43
  delete(request) {
49
44
  this.store.delete(request.url);
50
- (0, log_1.logCacheApiStatus)('DELETE-dev', request.url);
51
45
  }
52
46
  keys(request) {
53
47
  const cacheKeys = [];
@@ -0,0 +1,17 @@
1
+ import type { QueryKey, CachingStrategy } from '../types';
2
+ export declare function generateSubRequestCacheControlHeader(userCacheOptions?: CachingStrategy): string;
3
+ /**
4
+ * Get an item from the cache. If a match is found, returns a tuple
5
+ * containing the `JSON.parse` version of the response as well
6
+ * as the response itself so it can be checked for staleness.
7
+ */
8
+ export declare function getItemFromCache(key: QueryKey): Promise<undefined | [any, Response]>;
9
+ /**
10
+ * Put an item into the cache.
11
+ */
12
+ export declare function setItemInCache(key: QueryKey, value: any, userCacheOptions?: CachingStrategy): Promise<void>;
13
+ export declare function deleteItemFromCache(key: QueryKey): Promise<void>;
14
+ /**
15
+ * Manually check the response to see if it's stale.
16
+ */
17
+ export declare function isStale(key: QueryKey, response: Response): boolean;