@shopify/hydrogen 0.7.1 → 0.8.3
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/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.d.ts +1 -1
- package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.js +1 -1
- package/dist/esnext/components/CartLineQuantityAdjustButton/CartLineQuantityAdjustButton.js +4 -0
- package/dist/esnext/components/LocalizationProvider/index.d.ts +1 -0
- package/dist/esnext/components/LocalizationProvider/index.js +1 -0
- package/dist/esnext/components/ProductPrice/ProductPrice.client.d.ts +1 -3
- package/dist/esnext/components/ProductPrice/ProductPrice.client.js +1 -3
- package/dist/esnext/components/ShopPayButton/ShopPayButton.client.js +1 -1
- package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +1 -2
- package/dist/esnext/components/UnitPrice/UnitPrice.client.js +1 -2
- package/dist/esnext/components/index.d.ts +1 -0
- package/dist/esnext/components/index.js +1 -0
- package/dist/esnext/entry-client.js +4 -6
- package/dist/esnext/entry-server.js +70 -47
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.d.ts +2 -0
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.js +4 -0
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.d.ts +2 -0
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.js +5 -0
- package/dist/esnext/foundation/RenderCacheProvider/hook.d.ts +11 -0
- package/dist/esnext/foundation/RenderCacheProvider/hook.js +34 -0
- package/dist/esnext/foundation/RenderCacheProvider/index.d.ts +1 -0
- package/dist/esnext/foundation/RenderCacheProvider/index.js +1 -0
- package/dist/esnext/foundation/RenderCacheProvider/types.d.ts +18 -0
- package/dist/esnext/foundation/RenderCacheProvider/types.js +1 -0
- package/dist/esnext/foundation/Router/DefaultRoutes.d.ts +3 -1
- package/dist/esnext/foundation/Router/DefaultRoutes.js +2 -2
- package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.client.js +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.d.ts +1 -3
- package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.js +2 -4
- package/dist/esnext/foundation/ShopifyProvider/types.d.ts +0 -5
- package/dist/esnext/foundation/useQuery/hooks.d.ts +8 -6
- package/dist/esnext/foundation/useQuery/hooks.js +13 -14
- package/dist/esnext/foundation/useQuery/index.d.ts +0 -1
- package/dist/esnext/foundation/useQuery/index.js +0 -1
- package/dist/esnext/foundation/useShop/use-shop.d.ts +1 -1
- package/dist/esnext/foundation/useShop/use-shop.js +1 -1
- package/dist/esnext/framework/Hydration/ServerComponentRequest.server.d.ts +1 -0
- package/dist/esnext/framework/Hydration/ServerComponentRequest.server.js +2 -0
- package/dist/esnext/framework/cache.d.ts +2 -2
- package/dist/esnext/framework/cache.js +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.d.ts +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +13 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +7 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +15 -1
- package/dist/esnext/framework/plugins/vite-plugin-react-server-components-shim.js +1 -13
- package/dist/esnext/handle-event.d.ts +1 -1
- package/dist/esnext/handle-event.js +68 -10
- package/dist/esnext/hooks/index.d.ts +1 -1
- package/dist/esnext/hooks/index.js +1 -1
- package/dist/esnext/hooks/useShopQuery/hooks.d.ts +4 -4
- package/dist/esnext/hooks/useShopQuery/hooks.js +47 -20
- package/dist/esnext/index.d.ts +2 -1
- package/dist/esnext/index.js +2 -1
- package/dist/esnext/types.d.ts +2 -1
- package/dist/esnext/utilities/fetch.js +3 -6
- package/dist/esnext/utilities/index.d.ts +1 -0
- package/dist/esnext/utilities/index.js +1 -0
- package/dist/esnext/utilities/log/index.d.ts +1 -0
- package/dist/esnext/utilities/log/index.js +1 -0
- package/dist/esnext/utilities/log/log.d.ts +17 -0
- package/dist/esnext/utilities/log/log.js +75 -0
- package/dist/esnext/utilities/suspense.d.ts +2 -2
- package/dist/esnext/utilities/suspense.js +0 -6
- package/dist/esnext/utilities/timing.d.ts +7 -0
- package/dist/esnext/utilities/timing.js +14 -0
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/framework/Hydration/ServerComponentRequest.server.d.ts +1 -0
- package/dist/node/framework/Hydration/ServerComponentRequest.server.js +2 -0
- package/dist/node/framework/cache.d.ts +2 -2
- package/dist/node/framework/cache.js +2 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.d.ts +1 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +13 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +7 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +15 -1
- package/dist/node/framework/plugins/vite-plugin-react-server-components-shim.js +1 -13
- package/dist/node/handle-event.d.ts +1 -1
- package/dist/node/handle-event.js +68 -10
- package/dist/node/types.d.ts +2 -1
- package/dist/node/utilities/fetch.js +3 -6
- package/dist/node/utilities/index.d.ts +1 -0
- package/dist/node/utilities/index.js +3 -1
- package/dist/node/utilities/suspense.d.ts +2 -2
- package/dist/node/utilities/suspense.js +0 -6
- package/dist/node/utilities/timing.d.ts +7 -0
- package/dist/node/utilities/timing.js +18 -0
- package/dist/node/version.d.ts +1 -1
- package/dist/node/version.js +1 -1
- package/dist/worker/framework/Hydration/ServerComponentRequest.server.d.ts +1 -0
- package/dist/worker/framework/Hydration/ServerComponentRequest.server.js +2 -0
- package/dist/worker/framework/cache.d.ts +2 -2
- package/dist/worker/framework/cache.js +1 -1
- package/dist/worker/handle-event.d.ts +1 -1
- package/dist/worker/handle-event.js +68 -10
- package/dist/worker/types.d.ts +2 -1
- package/dist/worker/utilities/timing.d.ts +7 -0
- package/dist/worker/utilities/timing.js +14 -0
- package/package.json +10 -9
- package/dist/esnext/foundation/useQuery/QueryProvider.d.ts +0 -6
- package/dist/esnext/foundation/useQuery/QueryProvider.js +0 -13
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { yellow, red, green, italic, lightBlue } from 'kolorist';
|
|
2
|
+
import { getTime } from '../timing';
|
|
3
|
+
const defaultLogger = {
|
|
4
|
+
trace(context, ...args) {
|
|
5
|
+
console.log(...args);
|
|
6
|
+
},
|
|
7
|
+
debug(context, ...args) {
|
|
8
|
+
console.log(...args);
|
|
9
|
+
},
|
|
10
|
+
warn(context, ...args) {
|
|
11
|
+
console.warn(yellow('WARN: '), ...args);
|
|
12
|
+
},
|
|
13
|
+
error(context, ...args) {
|
|
14
|
+
console.error(red('ERROR: '), ...args);
|
|
15
|
+
},
|
|
16
|
+
fatal(context, ...args) {
|
|
17
|
+
console.error(red('FATAL: '), ...args);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
let logger = defaultLogger;
|
|
21
|
+
export function getLoggerFromContext(context) {
|
|
22
|
+
return {
|
|
23
|
+
trace: (...args) => logger.trace(context, ...args),
|
|
24
|
+
debug: (...args) => logger.debug(context, ...args),
|
|
25
|
+
warn: (...args) => logger.warn(context, ...args),
|
|
26
|
+
error: (...args) => logger.error(context, ...args),
|
|
27
|
+
fatal: (...args) => logger.fatal(context, ...args),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function setLogger(newLogger) {
|
|
31
|
+
logger = newLogger;
|
|
32
|
+
}
|
|
33
|
+
export function resetLogger() {
|
|
34
|
+
logger = defaultLogger;
|
|
35
|
+
}
|
|
36
|
+
export const log = {
|
|
37
|
+
trace(...args) {
|
|
38
|
+
return logger.trace({}, ...args);
|
|
39
|
+
},
|
|
40
|
+
debug(...args) {
|
|
41
|
+
return logger.debug({}, ...args);
|
|
42
|
+
},
|
|
43
|
+
warn(...args) {
|
|
44
|
+
return logger.warn({}, ...args);
|
|
45
|
+
},
|
|
46
|
+
error(...args) {
|
|
47
|
+
return logger.error({}, ...args);
|
|
48
|
+
},
|
|
49
|
+
fatal(...args) {
|
|
50
|
+
return logger.fatal({}, ...args);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
export function logServerResponse(type, log, request, responseStatus) {
|
|
54
|
+
const coloredResponseStatus = responseStatus >= 500
|
|
55
|
+
? red(responseStatus)
|
|
56
|
+
: responseStatus >= 400
|
|
57
|
+
? yellow(responseStatus)
|
|
58
|
+
: responseStatus >= 300
|
|
59
|
+
? lightBlue(responseStatus)
|
|
60
|
+
: green(responseStatus);
|
|
61
|
+
const fullType = type === 'str'
|
|
62
|
+
? 'streaming SSR'
|
|
63
|
+
: type === 'rsc'
|
|
64
|
+
? 'server components'
|
|
65
|
+
: 'buffered SSR';
|
|
66
|
+
const styledType = italic(pad(fullType, ' '));
|
|
67
|
+
const paddedTiming = pad((getTime() - request.time).toFixed(2) + ' ms', ' ');
|
|
68
|
+
const url = type === 'rsc'
|
|
69
|
+
? decodeURIComponent(request.url.substring(request.url.indexOf('=') + 1))
|
|
70
|
+
: request.url;
|
|
71
|
+
log.debug(`${request.method} ${styledType} ${coloredResponseStatus} ${paddedTiming} ${url}`);
|
|
72
|
+
}
|
|
73
|
+
function pad(str, _pad) {
|
|
74
|
+
return (str + _pad).substring(0, _pad.length);
|
|
75
|
+
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Wrap the fetch promise in a way that React Suspense understands.
|
|
3
3
|
* Essentially, keep throwing something until you have legit data.
|
|
4
4
|
*/
|
|
5
|
-
export declare function wrapPromise(promise: Promise<
|
|
6
|
-
read: () =>
|
|
5
|
+
export declare function wrapPromise<T>(promise: Promise<T>): {
|
|
6
|
+
read: () => T;
|
|
7
7
|
};
|
|
@@ -11,14 +11,8 @@ export function wrapPromise(promise) {
|
|
|
11
11
|
}, (err) => {
|
|
12
12
|
status = 'error';
|
|
13
13
|
response = err;
|
|
14
|
-
throw err;
|
|
15
14
|
});
|
|
16
15
|
const read = () => {
|
|
17
|
-
/**
|
|
18
|
-
* TODO: This logic doesn't hold up when an error is thrown. For some reason.
|
|
19
|
-
* We instead throw the exception above in the suspender. We should revisit
|
|
20
|
-
* this and add a better server fetch implementation.
|
|
21
|
-
*/
|
|
22
16
|
switch (status) {
|
|
23
17
|
case 'pending':
|
|
24
18
|
throw suspender;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Not all environments have access to Performance.now(). This is to prevent
|
|
3
|
+
* timing side channel attacks.
|
|
4
|
+
*
|
|
5
|
+
* See: https://community.cloudflare.com/t/cloudflare-workers-how-do-i-measure-execution-time-of-my-method/69672
|
|
6
|
+
*/
|
|
7
|
+
export declare function getTime(): number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Not all environments have access to Performance.now(). This is to prevent
|
|
3
|
+
* timing side channel attacks.
|
|
4
|
+
*
|
|
5
|
+
* See: https://community.cloudflare.com/t/cloudflare-workers-how-do-i-measure-execution-time-of-my-method/69672
|
|
6
|
+
*/
|
|
7
|
+
export function getTime() {
|
|
8
|
+
if (typeof performance !== 'undefined' && performance.now) {
|
|
9
|
+
return performance.now();
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
return Date.now();
|
|
13
|
+
}
|
|
14
|
+
}
|
package/dist/esnext/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "0.
|
|
1
|
+
export declare const LIB_VERSION = "0.8.3";
|
package/dist/esnext/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '0.
|
|
1
|
+
export const LIB_VERSION = '0.8.3';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ServerComponentRequest = void 0;
|
|
4
|
+
const timing_1 = require("../../utilities/timing");
|
|
4
5
|
/**
|
|
5
6
|
* This augments the `Request` object from the Fetch API:
|
|
6
7
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Request
|
|
@@ -19,6 +20,7 @@ class ServerComponentRequest extends Request {
|
|
|
19
20
|
method: input.method,
|
|
20
21
|
});
|
|
21
22
|
}
|
|
23
|
+
this.time = (0, timing_1.getTime)();
|
|
22
24
|
this.cookies = this.parseCookies();
|
|
23
25
|
}
|
|
24
26
|
parseCookies() {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { QueryKey } from '
|
|
2
|
-
import type { CacheOptions } from '../types';
|
|
1
|
+
import type { CacheOptions, QueryKey } from '../types';
|
|
3
2
|
export declare function generateCacheControlHeader(options: CacheOptions): string;
|
|
4
3
|
/**
|
|
5
4
|
* Use a preview header during development.
|
|
@@ -9,6 +8,7 @@ export declare function generateCacheControlHeader(options: CacheOptions): strin
|
|
|
9
8
|
export declare function getCacheControlHeader({ dev }: {
|
|
10
9
|
dev?: boolean;
|
|
11
10
|
}): "cache-control-preview" | "cache-control";
|
|
11
|
+
export declare function hashKey(key: QueryKey): string;
|
|
12
12
|
/**
|
|
13
13
|
* Get an item from the cache. If a match is found, returns a tuple
|
|
14
14
|
* containing the `JSON.parse` version of the response as well
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isStale = exports.deleteItemFromCache = exports.setItemInCache = exports.getItemFromCache = exports.getCacheControlHeader = exports.generateCacheControlHeader = void 0;
|
|
3
|
+
exports.isStale = exports.deleteItemFromCache = exports.setItemInCache = exports.getItemFromCache = exports.hashKey = exports.getCacheControlHeader = exports.generateCacheControlHeader = void 0;
|
|
4
4
|
const runtime_1 = require("./runtime");
|
|
5
5
|
const DEFAULT_SUBREQUEST_CACHE_OPTIONS = {
|
|
6
6
|
maxAge: 1,
|
|
@@ -33,6 +33,7 @@ function hashKey(key) {
|
|
|
33
33
|
*/
|
|
34
34
|
return rawKey.map((k) => JSON.stringify(k)).join('');
|
|
35
35
|
}
|
|
36
|
+
exports.hashKey = hashKey;
|
|
36
37
|
/**
|
|
37
38
|
* Cache API is weird. We just need a full URL, so we make one up.
|
|
38
39
|
*/
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.default = () => {
|
|
4
4
|
return {
|
|
5
5
|
name: 'vite-plugin-hydrogen-config',
|
|
6
|
-
config: (
|
|
6
|
+
config: async (config, env) => ({
|
|
7
7
|
resolve: {
|
|
8
8
|
alias: {
|
|
9
9
|
/**
|
|
@@ -18,6 +18,17 @@ exports.default = () => {
|
|
|
18
18
|
},
|
|
19
19
|
build: {
|
|
20
20
|
sourcemap: true,
|
|
21
|
+
/**
|
|
22
|
+
* By default, SSR dedupe logic gets bundled which runs `require('module')`.
|
|
23
|
+
* We don't want this in our workers runtime, because `require` is not supported.
|
|
24
|
+
*/
|
|
25
|
+
rollupOptions: process.env.WORKER
|
|
26
|
+
? {
|
|
27
|
+
output: {
|
|
28
|
+
format: 'es',
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
: {},
|
|
21
32
|
},
|
|
22
33
|
ssr: {
|
|
23
34
|
external: ['isomorphic-dompurify'],
|
|
@@ -57,6 +68,7 @@ exports.default = () => {
|
|
|
57
68
|
define: {
|
|
58
69
|
__DEV__: env.mode !== 'production',
|
|
59
70
|
},
|
|
71
|
+
envPrefix: ['VITE_', 'PUBLIC_'],
|
|
60
72
|
}),
|
|
61
73
|
};
|
|
62
74
|
};
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
2
|
import type { HydrogenVitePluginOptions, ShopifyConfig } from '../../types';
|
|
3
3
|
declare const _default: (shopifyConfig: ShopifyConfig, pluginOptions: HydrogenVitePluginOptions) => Plugin;
|
|
4
4
|
export default _default;
|
|
5
|
+
declare global {
|
|
6
|
+
var Oxygen: {
|
|
7
|
+
env: Record<string, string | undefined>;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vite_1 = require("vite");
|
|
6
7
|
const path_1 = __importDefault(require("path"));
|
|
7
8
|
const fs_1 = require("fs");
|
|
8
9
|
const middleware_1 = require("../middleware");
|
|
@@ -16,12 +17,13 @@ exports.default = (shopifyConfig, pluginOptions) => {
|
|
|
16
17
|
* loading them in an SSR context, rendering them using the `entry-server` endpoint in the
|
|
17
18
|
* user's project, and injecting the static HTML into the template.
|
|
18
19
|
*/
|
|
19
|
-
configureServer(server) {
|
|
20
|
+
async configureServer(server) {
|
|
20
21
|
const resolve = (p) => path_1.default.resolve(server.config.root, p);
|
|
21
22
|
async function getIndexTemplate(url) {
|
|
22
23
|
const indexHtml = await fs_1.promises.readFile(resolve('index.html'), 'utf-8');
|
|
23
24
|
return await server.transformIndexHtml(url, indexHtml);
|
|
24
25
|
}
|
|
26
|
+
await polyfillOxygenEnv(server.config);
|
|
25
27
|
// The default vite middleware rewrites the URL `/graphqil` to `/index.html`
|
|
26
28
|
// By running this middleware first, we avoid that.
|
|
27
29
|
server.middlewares.use((0, middleware_1.graphiqlMiddleware)({
|
|
@@ -41,3 +43,15 @@ exports.default = (shopifyConfig, pluginOptions) => {
|
|
|
41
43
|
},
|
|
42
44
|
};
|
|
43
45
|
};
|
|
46
|
+
async function polyfillOxygenEnv(config) {
|
|
47
|
+
const env = await (0, vite_1.loadEnv)(config.mode, config.root, '');
|
|
48
|
+
const publicPrefixes = Array.isArray(config.envPrefix)
|
|
49
|
+
? config.envPrefix
|
|
50
|
+
: [config.envPrefix || ''];
|
|
51
|
+
for (const key of Object.keys(env)) {
|
|
52
|
+
if (publicPrefixes.some((prefix) => key.startsWith(prefix))) {
|
|
53
|
+
delete env[key];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
globalThis.Oxygen = { env };
|
|
57
|
+
}
|
|
@@ -77,19 +77,7 @@ exports.default = () => {
|
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
79
|
};
|
|
80
|
-
// Mitigation for upcoming minor Vite update
|
|
81
|
-
// https://github.com/vitejs/vite/pull/5253
|
|
82
|
-
// TO-DO: When the vite package is updated with the above Vite PR,
|
|
83
|
-
// clean up this function and treat `options` param as objects
|
|
84
|
-
// from this point forward
|
|
85
|
-
// Timeline: Targetting for Vite 2.7
|
|
86
80
|
function isSSR(options) {
|
|
87
|
-
|
|
88
|
-
return options;
|
|
89
|
-
}
|
|
90
|
-
if (typeof options === 'object') {
|
|
91
|
-
return !!options.ssr;
|
|
92
|
-
}
|
|
93
|
-
return false;
|
|
81
|
+
return !!(options === null || options === void 0 ? void 0 : options.ssr);
|
|
94
82
|
}
|
|
95
83
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import
|
|
2
|
+
import { ServerResponse } from 'http';
|
|
3
3
|
import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
|
|
4
4
|
import { RuntimeContext } from './framework/runtime';
|
|
5
5
|
interface HydrogenFetchEvent {
|
|
@@ -29,7 +29,8 @@ async function handleEvent(event, { request, entrypoint, indexTemplate, assetHan
|
|
|
29
29
|
throw new Error(`entry-server.jsx could not be loaded. This likely occurred because of a Vite compilation error.\n` +
|
|
30
30
|
`Please check your server logs for more information.`);
|
|
31
31
|
}
|
|
32
|
-
const
|
|
32
|
+
const userAgent = request.headers.get('user-agent');
|
|
33
|
+
const isStreamable = streamableResponse && !isBotUA(url, userAgent);
|
|
33
34
|
/**
|
|
34
35
|
* Stream back real-user responses, but for bots/etc,
|
|
35
36
|
* use `render` instead. This is because we need to inject <head>
|
|
@@ -37,7 +38,12 @@ async function handleEvent(event, { request, entrypoint, indexTemplate, assetHan
|
|
|
37
38
|
*/
|
|
38
39
|
if (isStreamable) {
|
|
39
40
|
if (isReactHydrationRequest) {
|
|
40
|
-
hydrate(url, {
|
|
41
|
+
hydrate(url, {
|
|
42
|
+
context: {},
|
|
43
|
+
request,
|
|
44
|
+
response: streamableResponse,
|
|
45
|
+
dev,
|
|
46
|
+
});
|
|
41
47
|
}
|
|
42
48
|
else {
|
|
43
49
|
stream(url, {
|
|
@@ -50,7 +56,12 @@ async function handleEvent(event, { request, entrypoint, indexTemplate, assetHan
|
|
|
50
56
|
}
|
|
51
57
|
return;
|
|
52
58
|
}
|
|
53
|
-
const { body, bodyAttributes, htmlAttributes, componentResponse, ...head } = await render(url, {
|
|
59
|
+
const { body, bodyAttributes, htmlAttributes, componentResponse, ...head } = await render(url, {
|
|
60
|
+
request,
|
|
61
|
+
context: {},
|
|
62
|
+
isReactHydrationRequest,
|
|
63
|
+
dev,
|
|
64
|
+
});
|
|
54
65
|
const headers = componentResponse.headers;
|
|
55
66
|
/**
|
|
56
67
|
* TODO: Also add `Vary` headers for `accept-language` and any other keys
|
|
@@ -89,13 +100,6 @@ async function handleEvent(event, { request, entrypoint, indexTemplate, assetHan
|
|
|
89
100
|
return response;
|
|
90
101
|
}
|
|
91
102
|
exports.default = handleEvent;
|
|
92
|
-
function isStreamableRequest(url) {
|
|
93
|
-
/**
|
|
94
|
-
* TODO: Add UA detection.
|
|
95
|
-
*/
|
|
96
|
-
const isBot = url.searchParams.has('_bot');
|
|
97
|
-
return !isBot;
|
|
98
|
-
}
|
|
99
103
|
/**
|
|
100
104
|
* Generate the contents of the `head` tag, and update the existing `<title>` tag
|
|
101
105
|
* if one exists, and if a title is passed.
|
|
@@ -120,3 +124,57 @@ function generateHeadTag(head) {
|
|
|
120
124
|
return `<head>${headHtml}</head>`;
|
|
121
125
|
};
|
|
122
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Determines if the request is from a bot, using the URL and User Agent
|
|
129
|
+
*/
|
|
130
|
+
function isBotUA(url, userAgent) {
|
|
131
|
+
return (url.searchParams.has('_bot') || (!!userAgent && botUARegex.test(userAgent)));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* An alphabetized list of User Agents of known bots, combined from lists found at:
|
|
135
|
+
* https://github.com/vercel/next.js/blob/d87dc2b5a0b3fdbc0f6806a47be72bad59564bd0/packages/next/server/utils.ts#L18-L22
|
|
136
|
+
* https://github.com/GoogleChrome/rendertron/blob/6f681688737846b28754fbfdf5db173846a826df/middleware/src/middleware.ts#L24-L41
|
|
137
|
+
*/
|
|
138
|
+
const botUserAgents = [
|
|
139
|
+
'AdsBot-Google',
|
|
140
|
+
'applebot',
|
|
141
|
+
'Baiduspider',
|
|
142
|
+
'baiduspider',
|
|
143
|
+
'bingbot',
|
|
144
|
+
'Bingbot',
|
|
145
|
+
'BingPreview',
|
|
146
|
+
'bitlybot',
|
|
147
|
+
'Discordbot',
|
|
148
|
+
'DuckDuckBot',
|
|
149
|
+
'Embedly',
|
|
150
|
+
'facebookcatalog',
|
|
151
|
+
'facebookexternalhit',
|
|
152
|
+
'Google-PageRenderer',
|
|
153
|
+
'Googlebot',
|
|
154
|
+
'googleweblight',
|
|
155
|
+
'ia_archive',
|
|
156
|
+
'LinkedInBot',
|
|
157
|
+
'Mediapartners-Google',
|
|
158
|
+
'outbrain',
|
|
159
|
+
'pinterest',
|
|
160
|
+
'quora link preview',
|
|
161
|
+
'redditbot',
|
|
162
|
+
'rogerbot',
|
|
163
|
+
'showyoubot',
|
|
164
|
+
'SkypeUriPreview',
|
|
165
|
+
'Slackbot',
|
|
166
|
+
'Slurp',
|
|
167
|
+
'sogou',
|
|
168
|
+
'Storebot-Google',
|
|
169
|
+
'TelegramBot',
|
|
170
|
+
'tumblr',
|
|
171
|
+
'Twitterbot',
|
|
172
|
+
'vkShare',
|
|
173
|
+
'W3C_Validator',
|
|
174
|
+
'WhatsApp',
|
|
175
|
+
'yandex',
|
|
176
|
+
];
|
|
177
|
+
/**
|
|
178
|
+
* Creates a regex based on the botUserAgents array
|
|
179
|
+
*/
|
|
180
|
+
const botUARegex = new RegExp(botUserAgents.join('|'), 'i');
|
package/dist/node/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import
|
|
2
|
+
import { ServerResponse } from 'http';
|
|
3
3
|
import type { ServerComponentResponse } from './framework/Hydration/ServerComponentResponse.server';
|
|
4
4
|
import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
|
|
5
5
|
import type { Metafield, Image, MediaContentType } from './graphql/types/types';
|
|
@@ -78,6 +78,7 @@ export interface Measurement {
|
|
|
78
78
|
unit: string;
|
|
79
79
|
value: number;
|
|
80
80
|
}
|
|
81
|
+
export declare type QueryKey = string | readonly unknown[];
|
|
81
82
|
export interface CacheOptions {
|
|
82
83
|
private?: boolean;
|
|
83
84
|
maxAge?: number;
|
|
@@ -41,6 +41,9 @@ function fetchBuilder(request) {
|
|
|
41
41
|
headers,
|
|
42
42
|
method: clonedRequest.method,
|
|
43
43
|
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw response;
|
|
46
|
+
}
|
|
44
47
|
const data = await response.json();
|
|
45
48
|
return data;
|
|
46
49
|
};
|
|
@@ -55,12 +58,6 @@ function graphqlRequestBody(query, variables) {
|
|
|
55
58
|
}
|
|
56
59
|
exports.graphqlRequestBody = graphqlRequestBody;
|
|
57
60
|
function decodeShopifyId(id) {
|
|
58
|
-
if (!id.startsWith('gid://')) {
|
|
59
|
-
id =
|
|
60
|
-
typeof btoa !== 'undefined'
|
|
61
|
-
? btoa(id)
|
|
62
|
-
: Buffer.from(id, 'base64').toString('ascii');
|
|
63
|
-
}
|
|
64
61
|
if (!id.startsWith('gid://')) {
|
|
65
62
|
throw new Error('invalid Shopify ID');
|
|
66
63
|
}
|
|
@@ -8,3 +8,4 @@ export { isServer } from './isServer';
|
|
|
8
8
|
export { getMeasurementAsParts, getMeasurementAsString } from './measurement';
|
|
9
9
|
export { parseMetafieldValue } from './parseMetafieldValue';
|
|
10
10
|
export { fetchBuilder, graphqlRequestBody, decodeShopifyId } from './fetch';
|
|
11
|
+
export { getTime } from './timing';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.decodeShopifyId = exports.graphqlRequestBody = exports.fetchBuilder = exports.parseMetafieldValue = exports.getMeasurementAsString = exports.getMeasurementAsParts = exports.isServer = exports.isClient = exports.flattenConnection = exports.wrapPromise = exports.loadScript = exports.useEmbeddedVideoUrl = exports.addParametersToEmbeddedVideoUrl = exports.shopifyImageLoader = exports.getShopifyImageDimensions = exports.useImageUrl = exports.addImageSizeParametersToUrl = void 0;
|
|
3
|
+
exports.getTime = exports.decodeShopifyId = exports.graphqlRequestBody = exports.fetchBuilder = exports.parseMetafieldValue = exports.getMeasurementAsString = exports.getMeasurementAsParts = exports.isServer = exports.isClient = exports.flattenConnection = exports.wrapPromise = exports.loadScript = exports.useEmbeddedVideoUrl = exports.addParametersToEmbeddedVideoUrl = exports.shopifyImageLoader = exports.getShopifyImageDimensions = exports.useImageUrl = exports.addImageSizeParametersToUrl = void 0;
|
|
4
4
|
var image_size_1 = require("./image_size");
|
|
5
5
|
Object.defineProperty(exports, "addImageSizeParametersToUrl", { enumerable: true, get: function () { return image_size_1.addImageSizeParametersToUrl; } });
|
|
6
6
|
Object.defineProperty(exports, "useImageUrl", { enumerable: true, get: function () { return image_size_1.useImageUrl; } });
|
|
@@ -28,3 +28,5 @@ var fetch_1 = require("./fetch");
|
|
|
28
28
|
Object.defineProperty(exports, "fetchBuilder", { enumerable: true, get: function () { return fetch_1.fetchBuilder; } });
|
|
29
29
|
Object.defineProperty(exports, "graphqlRequestBody", { enumerable: true, get: function () { return fetch_1.graphqlRequestBody; } });
|
|
30
30
|
Object.defineProperty(exports, "decodeShopifyId", { enumerable: true, get: function () { return fetch_1.decodeShopifyId; } });
|
|
31
|
+
var timing_1 = require("./timing");
|
|
32
|
+
Object.defineProperty(exports, "getTime", { enumerable: true, get: function () { return timing_1.getTime; } });
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Wrap the fetch promise in a way that React Suspense understands.
|
|
3
3
|
* Essentially, keep throwing something until you have legit data.
|
|
4
4
|
*/
|
|
5
|
-
export declare function wrapPromise(promise: Promise<
|
|
6
|
-
read: () =>
|
|
5
|
+
export declare function wrapPromise<T>(promise: Promise<T>): {
|
|
6
|
+
read: () => T;
|
|
7
7
|
};
|
|
@@ -14,14 +14,8 @@ function wrapPromise(promise) {
|
|
|
14
14
|
}, (err) => {
|
|
15
15
|
status = 'error';
|
|
16
16
|
response = err;
|
|
17
|
-
throw err;
|
|
18
17
|
});
|
|
19
18
|
const read = () => {
|
|
20
|
-
/**
|
|
21
|
-
* TODO: This logic doesn't hold up when an error is thrown. For some reason.
|
|
22
|
-
* We instead throw the exception above in the suspender. We should revisit
|
|
23
|
-
* this and add a better server fetch implementation.
|
|
24
|
-
*/
|
|
25
19
|
switch (status) {
|
|
26
20
|
case 'pending':
|
|
27
21
|
throw suspender;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Not all environments have access to Performance.now(). This is to prevent
|
|
3
|
+
* timing side channel attacks.
|
|
4
|
+
*
|
|
5
|
+
* See: https://community.cloudflare.com/t/cloudflare-workers-how-do-i-measure-execution-time-of-my-method/69672
|
|
6
|
+
*/
|
|
7
|
+
export declare function getTime(): number;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTime = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Not all environments have access to Performance.now(). This is to prevent
|
|
6
|
+
* timing side channel attacks.
|
|
7
|
+
*
|
|
8
|
+
* See: https://community.cloudflare.com/t/cloudflare-workers-how-do-i-measure-execution-time-of-my-method/69672
|
|
9
|
+
*/
|
|
10
|
+
function getTime() {
|
|
11
|
+
if (typeof performance !== 'undefined' && performance.now) {
|
|
12
|
+
return performance.now();
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return Date.now();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.getTime = getTime;
|
package/dist/node/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "0.
|
|
1
|
+
export declare const LIB_VERSION = "0.8.3";
|
package/dist/node/version.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getTime } from '../../utilities/timing';
|
|
1
2
|
/**
|
|
2
3
|
* This augments the `Request` object from the Fetch API:
|
|
3
4
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Request
|
|
@@ -16,6 +17,7 @@ export class ServerComponentRequest extends Request {
|
|
|
16
17
|
method: input.method,
|
|
17
18
|
});
|
|
18
19
|
}
|
|
20
|
+
this.time = getTime();
|
|
19
21
|
this.cookies = this.parseCookies();
|
|
20
22
|
}
|
|
21
23
|
parseCookies() {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { QueryKey } from '
|
|
2
|
-
import type { CacheOptions } from '../types';
|
|
1
|
+
import type { CacheOptions, QueryKey } from '../types';
|
|
3
2
|
export declare function generateCacheControlHeader(options: CacheOptions): string;
|
|
4
3
|
/**
|
|
5
4
|
* Use a preview header during development.
|
|
@@ -9,6 +8,7 @@ export declare function generateCacheControlHeader(options: CacheOptions): strin
|
|
|
9
8
|
export declare function getCacheControlHeader({ dev }: {
|
|
10
9
|
dev?: boolean;
|
|
11
10
|
}): "cache-control-preview" | "cache-control";
|
|
11
|
+
export declare function hashKey(key: QueryKey): string;
|
|
12
12
|
/**
|
|
13
13
|
* Get an item from the cache. If a match is found, returns a tuple
|
|
14
14
|
* containing the `JSON.parse` version of the response as well
|
|
@@ -21,7 +21,7 @@ export function generateCacheControlHeader(options) {
|
|
|
21
21
|
export function getCacheControlHeader({ dev }) {
|
|
22
22
|
return dev ? 'cache-control-preview' : 'cache-control';
|
|
23
23
|
}
|
|
24
|
-
function hashKey(key) {
|
|
24
|
+
export function hashKey(key) {
|
|
25
25
|
const rawKey = key instanceof Array ? key : [key];
|
|
26
26
|
/**
|
|
27
27
|
* TODO: Smarter hash
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@types/node" />
|
|
2
|
-
import
|
|
2
|
+
import { ServerResponse } from 'http';
|
|
3
3
|
import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
|
|
4
4
|
import { RuntimeContext } from './framework/runtime';
|
|
5
5
|
interface HydrogenFetchEvent {
|