@opennextjs/cloudflare 0.5.1 → 0.5.2
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.
|
@@ -23,7 +23,12 @@ export type CloudflareContext<CfProperties extends Record<string, unknown> = Inc
|
|
|
23
23
|
*
|
|
24
24
|
* @returns the cloudflare context
|
|
25
25
|
*/
|
|
26
|
-
export declare function getCloudflareContext<CfProperties extends Record<string, unknown> = IncomingRequestCfProperties, Context = ExecutionContext>(
|
|
26
|
+
export declare function getCloudflareContext<CfProperties extends Record<string, unknown> = IncomingRequestCfProperties, Context = ExecutionContext>(options: {
|
|
27
|
+
async: true;
|
|
28
|
+
}): Promise<CloudflareContext<CfProperties, Context>>;
|
|
29
|
+
export declare function getCloudflareContext<CfProperties extends Record<string, unknown> = IncomingRequestCfProperties, Context = ExecutionContext>(options?: {
|
|
30
|
+
async: false;
|
|
31
|
+
}): CloudflareContext<CfProperties, Context>;
|
|
27
32
|
/**
|
|
28
33
|
* Performs some initial setup to integrate as best as possible the local Next.js dev server (run via `next dev`)
|
|
29
34
|
* with the open-next Cloudflare adapter
|
|
@@ -6,41 +6,65 @@
|
|
|
6
6
|
* Note: this symbol needs to be kept in sync with the one used in `src/cli/templates/worker.ts`
|
|
7
7
|
*/
|
|
8
8
|
const cloudflareContextSymbol = Symbol.for("__cloudflare-context__");
|
|
9
|
+
export function getCloudflareContext(options = { async: false }) {
|
|
10
|
+
return options.async ? getCloudflareContextAsync() : getCloudflareContextSync();
|
|
11
|
+
}
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
* Get the cloudflare context from the current global scope
|
|
14
|
+
*/
|
|
15
|
+
function getCloudflareContextFromGlobalScope() {
|
|
16
|
+
const global = globalThis;
|
|
17
|
+
return global[cloudflareContextSymbol];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Detects whether the current code is being evaluated in a statically generated route
|
|
13
21
|
*/
|
|
14
|
-
|
|
22
|
+
function inSSG() {
|
|
15
23
|
const global = globalThis;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
`
|
|
35
|
-
|
|
36
|
-
`
|
|
37
|
-
`
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
24
|
+
// Note: Next.js sets globalThis.__NEXT_DATA__.nextExport to true for SSG routes
|
|
25
|
+
// source: https://github.com/vercel/next.js/blob/4e394608423/packages/next/src/export/worker.ts#L55-L57)
|
|
26
|
+
return global.__NEXT_DATA__?.nextExport === true;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Utility to get the current Cloudflare context in sync mode
|
|
30
|
+
*/
|
|
31
|
+
function getCloudflareContextSync() {
|
|
32
|
+
const cloudflareContext = getCloudflareContextFromGlobalScope();
|
|
33
|
+
if (cloudflareContext) {
|
|
34
|
+
return cloudflareContext;
|
|
35
|
+
}
|
|
36
|
+
// The sync mode of `getCloudflareContext`, relies on the context being set on the global state
|
|
37
|
+
// by either the worker entrypoint (in prod) or by `initOpenNextCloudflareForDev` (in dev), neither
|
|
38
|
+
// can work during SSG since for SSG Next.js creates (jest) workers that don't get access to the
|
|
39
|
+
// normal global state so we throw with a helpful error message.
|
|
40
|
+
if (inSSG()) {
|
|
41
|
+
throw new Error(`\n\nERROR: \`getCloudflareContext\` has been called in a static route,` +
|
|
42
|
+
` that is not allowed, this can be solved in different ways:\n\n` +
|
|
43
|
+
` - call \`getCloudflareContext({async: true})\` to use the \`async\` mode\n` +
|
|
44
|
+
` - avoid calling \`getCloudflareContext\` in the route\n` +
|
|
45
|
+
` - make the route non static\n`);
|
|
46
|
+
}
|
|
47
|
+
throw new Error(initOpenNextCloudflareForDevErrorMsg);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Utility to get the current Cloudflare context in async mode
|
|
51
|
+
*/
|
|
52
|
+
async function getCloudflareContextAsync() {
|
|
53
|
+
const cloudflareContext = getCloudflareContextFromGlobalScope();
|
|
54
|
+
if (cloudflareContext) {
|
|
55
|
+
return cloudflareContext;
|
|
56
|
+
}
|
|
57
|
+
// Note: Next.js sets process.env.NEXT_RUNTIME to 'nodejs' when the runtime in use is the node.js one
|
|
58
|
+
// We want to detect when the runtime is the node.js one so that during development (`next dev`) we know wether
|
|
59
|
+
// we are or not in a node.js process and that access to wrangler's node.js apis
|
|
60
|
+
const inNodejsRuntime = process.env.NEXT_RUNTIME === "nodejs";
|
|
61
|
+
if (inNodejsRuntime || inSSG()) {
|
|
62
|
+
// we're in a node.js process and also in "async mode" so we can use wrangler to asynchronously get the context
|
|
63
|
+
const cloudflareContext = await getCloudflareContextFromWrangler();
|
|
64
|
+
addCloudflareContextToNodejsGlobal(cloudflareContext);
|
|
65
|
+
return cloudflareContext;
|
|
42
66
|
}
|
|
43
|
-
|
|
67
|
+
throw new Error(initOpenNextCloudflareForDevErrorMsg);
|
|
44
68
|
}
|
|
45
69
|
/**
|
|
46
70
|
* Performs some initial setup to integrate as best as possible the local Next.js dev server (run via `next dev`)
|
|
@@ -72,7 +96,7 @@ function shouldContextInitializationRun() {
|
|
|
72
96
|
return !!AsyncLocalStorage;
|
|
73
97
|
}
|
|
74
98
|
/**
|
|
75
|
-
* Adds the cloudflare context to the global scope
|
|
99
|
+
* Adds the cloudflare context to the global scope of the current node.js process, enabling
|
|
76
100
|
* future calls to `getCloudflareContext` to retrieve and return such context
|
|
77
101
|
*
|
|
78
102
|
* @param cloudflareContext the cloudflare context to add to the node.sj global scope
|
|
@@ -120,3 +144,16 @@ async function getCloudflareContextFromWrangler() {
|
|
|
120
144
|
ctx: ctx,
|
|
121
145
|
};
|
|
122
146
|
}
|
|
147
|
+
// In production the cloudflare context is initialized by the worker so it is always available.
|
|
148
|
+
// During local development (`next dev`) it might be missing only if the developers hasn't called
|
|
149
|
+
// the `initOpenNextCloudflareForDev` function in their Next.js config file
|
|
150
|
+
const initOpenNextCloudflareForDevErrorMsg = `\n\nERROR: \`getCloudflareContext\` has been called without having called` +
|
|
151
|
+
` \`initOpenNextCloudflareForDev\` from the Next.js config file.\n` +
|
|
152
|
+
`You should update your Next.js config file as shown below:\n\n` +
|
|
153
|
+
" ```\n // next.config.mjs\n\n" +
|
|
154
|
+
` import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";\n\n` +
|
|
155
|
+
` initOpenNextCloudflareForDev();\n\n` +
|
|
156
|
+
" const nextConfig = { ... };\n" +
|
|
157
|
+
" export default nextConfig;\n" +
|
|
158
|
+
" ```\n" +
|
|
159
|
+
"\n";
|
|
@@ -6,13 +6,11 @@ import { handler as middlewareHandler } from "./middleware/handler.mjs";
|
|
|
6
6
|
// @ts-expect-error: resolved by wrangler build
|
|
7
7
|
import { handler as serverHandler } from "./server-functions/default/handler.mjs";
|
|
8
8
|
const cloudflareContextALS = new AsyncLocalStorage();
|
|
9
|
-
// Note: this symbol needs to be kept in sync with
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
get: (_, property) => Reflect.get(cloudflareContextALS.getStore(), property),
|
|
15
|
-
set: (_, property, value) => Reflect.set(cloudflareContextALS.getStore(), property, value),
|
|
9
|
+
// Note: this symbol needs to be kept in sync with `src/api/get-cloudflare-context.ts`
|
|
10
|
+
Object.defineProperty(globalThis, Symbol.for("__cloudflare-context__"), {
|
|
11
|
+
get() {
|
|
12
|
+
return cloudflareContextALS.getStore();
|
|
13
|
+
},
|
|
16
14
|
});
|
|
17
15
|
// Populate process.env on the first request
|
|
18
16
|
let processEnvPopulated = false;
|