@opennextjs/cloudflare 1.16.6 → 1.17.1
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/cli/build/build.js +1 -1
- package/dist/cli/build/bundle-server.js +3 -1
- package/dist/cli/build/open-next/compile-env-files.js +1 -1
- package/dist/cli/build/open-next/createServerBundle.js +1 -1
- package/dist/cli/build/patches/plugins/dynamic-requires.js +1 -1
- package/dist/cli/build/patches/plugins/instrumentation.js +1 -1
- package/dist/cli/build/patches/plugins/load-manifest.js +1 -1
- package/dist/cli/build/patches/plugins/next-server.js +1 -1
- package/dist/cli/build/patches/plugins/route-module.js +1 -1
- package/dist/cli/build/patches/plugins/wrangler-external.js +1 -1
- package/dist/cli/build/utils/index.d.ts +0 -6
- package/dist/cli/build/utils/index.js +1 -6
- package/dist/cli/commands/build.d.ts +13 -0
- package/dist/cli/commands/build.js +16 -4
- package/dist/cli/commands/deploy.d.ts +1 -1
- package/dist/cli/commands/deploy.js +9 -4
- package/dist/cli/commands/migrate.js +16 -8
- package/dist/cli/commands/populate-cache.d.ts +2 -2
- package/dist/cli/commands/populate-cache.js +19 -7
- package/dist/cli/commands/preview.d.ts +1 -1
- package/dist/cli/commands/preview.js +9 -4
- package/dist/cli/commands/skew-protection.d.ts +1 -1
- package/dist/cli/commands/upload.d.ts +1 -1
- package/dist/cli/commands/upload.js +9 -4
- package/dist/cli/commands/{helpers.js → utils/helpers.js} +1 -1
- package/dist/cli/commands/utils/run-wrangler.d.ts +44 -0
- package/dist/cli/{utils → commands/utils}/run-wrangler.js +46 -11
- package/dist/cli/commands/{utils.d.ts → utils/utils.d.ts} +6 -12
- package/dist/cli/commands/{utils.js → utils/utils.js} +14 -26
- package/dist/cli/project-options.d.ts +1 -1
- package/dist/cli/templates/images.d.ts +30 -0
- package/dist/cli/templates/images.js +130 -13
- package/dist/cli/templates/worker.js +2 -9
- package/dist/cli/utils/ask-account-selection.d.ts +12 -0
- package/dist/cli/utils/ask-account-selection.js +23 -0
- package/dist/cli/utils/create-open-next-config.d.ts +17 -0
- package/dist/cli/utils/create-open-next-config.js +50 -0
- package/dist/cli/utils/create-wrangler-config.d.ts +24 -0
- package/dist/cli/utils/create-wrangler-config.js +244 -0
- package/dist/cli/utils/nextjs-support.d.ts +10 -0
- package/dist/cli/utils/nextjs-support.js +24 -0
- package/package.json +3 -2
- package/templates/open-next.config.ts +1 -1
- package/templates/wrangler.jsonc +2 -2
- package/dist/cli/build/utils/create-config-files.d.ts +0 -19
- package/dist/cli/build/utils/create-config-files.js +0 -44
- package/dist/cli/utils/open-next-config.d.ts +0 -14
- package/dist/cli/utils/open-next-config.js +0 -27
- package/dist/cli/utils/run-wrangler.d.ts +0 -12
- package/dist/cli/utils/wrangler-config.d.ts +0 -15
- package/dist/cli/utils/wrangler-config.js +0 -64
- /package/dist/cli/{build → commands}/utils/files.d.ts +0 -0
- /package/dist/cli/{build → commands}/utils/files.js +0 -0
- /package/dist/cli/commands/{helpers.d.ts → utils/helpers.d.ts} +0 -0
- /package/dist/cli/{build/utils → utils}/extract-project-env-vars.d.ts +0 -0
- /package/dist/cli/{build/utils → utils}/extract-project-env-vars.js +0 -0
- /package/dist/cli/{build/utils → utils}/normalize-path.d.ts +0 -0
- /package/dist/cli/{build/utils → utils}/normalize-path.js +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import * as buildHelper from "@opennextjs/aws/build/helper.js";
|
|
2
1
|
import type yargs from "yargs";
|
|
3
|
-
import type { OpenNextConfig } from "
|
|
2
|
+
import type { OpenNextConfig } from "../../../api/config.js";
|
|
4
3
|
export type WithWranglerArgs<T = unknown> = T & {
|
|
5
4
|
wranglerArgs: string[];
|
|
6
5
|
wranglerConfigPath: string | undefined;
|
|
@@ -13,15 +12,6 @@ export declare const nextAppDir: string;
|
|
|
13
12
|
* @param command
|
|
14
13
|
*/
|
|
15
14
|
export declare function printHeaders(command: string): void;
|
|
16
|
-
/**
|
|
17
|
-
* Validates that the Next.js version is supported and checks wrangler compatibility.
|
|
18
|
-
*
|
|
19
|
-
* Note: this function assumes that wrangler is installed.
|
|
20
|
-
*
|
|
21
|
-
* @param options.nextVersion The detected Next.js version string
|
|
22
|
-
* @throws {Error} If the Next.js version is unsupported
|
|
23
|
-
*/
|
|
24
|
-
export declare function ensureNextjsVersionSupported({ nextVersion, }: Pick<buildHelper.BuildOptions, "nextVersion">): Promise<void>;
|
|
25
15
|
/**
|
|
26
16
|
* Compile the OpenNext config.
|
|
27
17
|
*
|
|
@@ -30,8 +20,12 @@ export declare function ensureNextjsVersionSupported({ nextVersion, }: Pick<buil
|
|
|
30
20
|
*
|
|
31
21
|
* When users specify a custom config file but it doesn't exist, we throw an Error.
|
|
32
22
|
*
|
|
23
|
+
* @throws If a custom config path is provided but the file does not exist.
|
|
24
|
+
* @throws If no config file is found and the user declines to create one.
|
|
25
|
+
*
|
|
33
26
|
* @param configPath Optional path to the config file. Absolute or relative to cwd.
|
|
34
|
-
* @returns OpenNext config.
|
|
27
|
+
* @returns The compiled OpenNext config and the build directory.
|
|
28
|
+
*
|
|
35
29
|
*/
|
|
36
30
|
export declare function compileConfig(configPath: string | undefined): Promise<{
|
|
37
31
|
config: import("@opennextjs/aws/types/open-next.js").OpenNextConfig;
|
|
@@ -4,11 +4,12 @@ import path from "node:path";
|
|
|
4
4
|
import url from "node:url";
|
|
5
5
|
import { compileOpenNextConfig } from "@opennextjs/aws/build/compileConfig.js";
|
|
6
6
|
import { normalizeOptions } from "@opennextjs/aws/build/helper.js";
|
|
7
|
-
import * as buildHelper from "@opennextjs/aws/build/helper.js";
|
|
8
7
|
import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.js";
|
|
9
8
|
import logger from "@opennextjs/aws/logger.js";
|
|
10
9
|
import { unstable_readConfig } from "wrangler";
|
|
11
|
-
import {
|
|
10
|
+
import { ensureCloudflareConfig } from "../../build/utils/ensure-cf-config.js";
|
|
11
|
+
import { askConfirmation } from "../../utils/ask-confirmation.js";
|
|
12
|
+
import { createOpenNextConfigFile, findOpenNextConfig } from "../../utils/create-open-next-config.js";
|
|
12
13
|
export const nextAppDir = process.cwd();
|
|
13
14
|
/**
|
|
14
15
|
* Print headers and warnings for the CLI.
|
|
@@ -19,28 +20,6 @@ export function printHeaders(command) {
|
|
|
19
20
|
printHeader(`Cloudflare ${command}`);
|
|
20
21
|
showWarningOnWindows();
|
|
21
22
|
}
|
|
22
|
-
/**
|
|
23
|
-
* Validates that the Next.js version is supported and checks wrangler compatibility.
|
|
24
|
-
*
|
|
25
|
-
* Note: this function assumes that wrangler is installed.
|
|
26
|
-
*
|
|
27
|
-
* @param options.nextVersion The detected Next.js version string
|
|
28
|
-
* @throws {Error} If the Next.js version is unsupported
|
|
29
|
-
*/
|
|
30
|
-
export async function ensureNextjsVersionSupported({ nextVersion, }) {
|
|
31
|
-
if (buildHelper.compareSemver(nextVersion, "<", "14.2.0")) {
|
|
32
|
-
throw new Error("Next.js version unsupported, please upgrade to version 14.2 or greater.");
|
|
33
|
-
}
|
|
34
|
-
const { default: { version: wranglerVersion }, } = await import("wrangler/package.json", { with: { type: "json" } });
|
|
35
|
-
// We need a version of workerd that has a fix for setImmediate for Next.js 16.1+
|
|
36
|
-
// See:
|
|
37
|
-
// - https://github.com/cloudflare/workerd/pull/5869
|
|
38
|
-
// - https://github.com/opennextjs/opennextjs-cloudflare/issues/1049
|
|
39
|
-
if (buildHelper.compareSemver(nextVersion, ">=", "16.1.0") &&
|
|
40
|
-
buildHelper.compareSemver(wranglerVersion, "<", "4.59.2")) {
|
|
41
|
-
logger.warn(`Next.js 16.1+ requires wrangler 4.59.2 or greater (${wranglerVersion} detected).`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
23
|
/**
|
|
45
24
|
* Compile the OpenNext config.
|
|
46
25
|
*
|
|
@@ -49,15 +28,24 @@ export async function ensureNextjsVersionSupported({ nextVersion, }) {
|
|
|
49
28
|
*
|
|
50
29
|
* When users specify a custom config file but it doesn't exist, we throw an Error.
|
|
51
30
|
*
|
|
31
|
+
* @throws If a custom config path is provided but the file does not exist.
|
|
32
|
+
* @throws If no config file is found and the user declines to create one.
|
|
33
|
+
*
|
|
52
34
|
* @param configPath Optional path to the config file. Absolute or relative to cwd.
|
|
53
|
-
* @returns OpenNext config.
|
|
35
|
+
* @returns The compiled OpenNext config and the build directory.
|
|
36
|
+
*
|
|
54
37
|
*/
|
|
55
38
|
export async function compileConfig(configPath) {
|
|
56
39
|
if (configPath && !existsSync(configPath)) {
|
|
57
40
|
throw new Error(`Custom config file not found at ${configPath}`);
|
|
58
41
|
}
|
|
42
|
+
configPath ??= findOpenNextConfig(nextAppDir);
|
|
59
43
|
if (!configPath) {
|
|
60
|
-
|
|
44
|
+
const answer = await askConfirmation("Missing required `open-next.config.ts` file, do you want to create one?");
|
|
45
|
+
if (!answer) {
|
|
46
|
+
throw new Error("The `open-next.config.ts` file is required, aborting!");
|
|
47
|
+
}
|
|
48
|
+
configPath = createOpenNextConfigFile(nextAppDir, { cache: false });
|
|
61
49
|
}
|
|
62
50
|
const { config, buildDir } = await compileOpenNextConfig(configPath, { compileEdge: true });
|
|
63
51
|
ensureCloudflareConfig(config);
|
|
@@ -22,7 +22,37 @@ export type LocalPattern = {
|
|
|
22
22
|
* @returns A promise that resolves to the resolved request.
|
|
23
23
|
*/
|
|
24
24
|
export declare function handleImageRequest(requestURL: URL, requestHeaders: Headers, env: CloudflareEnv): Promise<Response>;
|
|
25
|
+
/**
|
|
26
|
+
* Handles requests to /cdn-cgi/image/ in development.
|
|
27
|
+
*
|
|
28
|
+
* Extracts the image URL, fetches the image, and checks the content type against
|
|
29
|
+
* Cloudflare's supported input formats.
|
|
30
|
+
*
|
|
31
|
+
* @param requestURL The full request URL.
|
|
32
|
+
* @param env The Cloudflare environment bindings.
|
|
33
|
+
* @returns A promise that resolves to the image response.
|
|
34
|
+
*/
|
|
35
|
+
export declare function handleCdnCgiImageRequest(requestURL: URL, env: CloudflareEnv): Promise<Response>;
|
|
36
|
+
/**
|
|
37
|
+
* Parses a /cdn-cgi/image/ request URL.
|
|
38
|
+
*
|
|
39
|
+
* Extracts the image URL from the `/cdn-cgi/image/<options>/<image-url>` path format.
|
|
40
|
+
* Rejects protocol-relative URLs (`//...`). The cdn-cgi options are not parsed or
|
|
41
|
+
* validated as they are Cloudflare's concern.
|
|
42
|
+
*
|
|
43
|
+
* @param pathname The URL pathname (e.g. `/cdn-cgi/image/width=640,quality=75,format=auto/path/to/image.png`).
|
|
44
|
+
* @returns the parsed URL result or an error.
|
|
45
|
+
*/
|
|
46
|
+
export declare function parseCdnCgiImageRequest(pathname: string): {
|
|
47
|
+
ok: true;
|
|
48
|
+
url: string;
|
|
49
|
+
static: boolean;
|
|
50
|
+
} | ErrorResult;
|
|
25
51
|
export type OptimizedImageFormat = "image/avif" | "image/webp";
|
|
52
|
+
type ErrorResult = {
|
|
53
|
+
ok: false;
|
|
54
|
+
message: string;
|
|
55
|
+
};
|
|
26
56
|
export declare function matchLocalPattern(pattern: LocalPattern, url: {
|
|
27
57
|
pathname: string;
|
|
28
58
|
search: string;
|
|
@@ -68,19 +68,11 @@ export async function handleImageRequest(requestURL, requestHeaders, env) {
|
|
|
68
68
|
immutable = cacheControlHeader.includes("immutable");
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
mode: "byob",
|
|
75
|
-
});
|
|
76
|
-
const readImageHeaderBytesResult = await contentTypeImageReader.readAtLeast(32, imageHeaderBytes);
|
|
77
|
-
if (readImageHeaderBytesResult.value === undefined) {
|
|
78
|
-
await imageResponse.body.cancel();
|
|
79
|
-
return new Response('"url" parameter is valid but upstream response is invalid', {
|
|
80
|
-
status: 400,
|
|
81
|
-
});
|
|
71
|
+
const readHeaderResult = await readImageHeader(imageResponse);
|
|
72
|
+
if (readHeaderResult instanceof Response) {
|
|
73
|
+
return readHeaderResult;
|
|
82
74
|
}
|
|
83
|
-
const contentType =
|
|
75
|
+
const { contentType, imageStream } = readHeaderResult;
|
|
84
76
|
if (contentType === null) {
|
|
85
77
|
warn(`Failed to detect content type of "${parseResult.url}"`);
|
|
86
78
|
return new Response('"url" parameter is valid but image type is not allowed', {
|
|
@@ -153,6 +145,123 @@ export async function handleImageRequest(requestURL, requestHeaders, env) {
|
|
|
153
145
|
});
|
|
154
146
|
return response;
|
|
155
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Handles requests to /cdn-cgi/image/ in development.
|
|
150
|
+
*
|
|
151
|
+
* Extracts the image URL, fetches the image, and checks the content type against
|
|
152
|
+
* Cloudflare's supported input formats.
|
|
153
|
+
*
|
|
154
|
+
* @param requestURL The full request URL.
|
|
155
|
+
* @param env The Cloudflare environment bindings.
|
|
156
|
+
* @returns A promise that resolves to the image response.
|
|
157
|
+
*/
|
|
158
|
+
export async function handleCdnCgiImageRequest(requestURL, env) {
|
|
159
|
+
const parseResult = parseCdnCgiImageRequest(requestURL.pathname);
|
|
160
|
+
if (!parseResult.ok) {
|
|
161
|
+
return new Response(parseResult.message, {
|
|
162
|
+
status: 400,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
let imageResponse;
|
|
166
|
+
if (parseResult.url.startsWith("/")) {
|
|
167
|
+
if (env.ASSETS === undefined) {
|
|
168
|
+
return new Response("env.ASSETS binding is not defined", {
|
|
169
|
+
status: 404,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const absoluteURL = new URL(parseResult.url, requestURL);
|
|
173
|
+
imageResponse = await env.ASSETS.fetch(absoluteURL);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
imageResponse = await fetch(parseResult.url);
|
|
177
|
+
}
|
|
178
|
+
if (!imageResponse.ok || imageResponse.body === null) {
|
|
179
|
+
return new Response('"url" parameter is valid but upstream response is invalid', {
|
|
180
|
+
status: imageResponse.status,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const readHeaderResult = await readImageHeader(imageResponse);
|
|
184
|
+
if (readHeaderResult instanceof Response) {
|
|
185
|
+
return readHeaderResult;
|
|
186
|
+
}
|
|
187
|
+
const { contentType, imageStream } = readHeaderResult;
|
|
188
|
+
if (contentType === null || !SUPPORTED_CDN_CGI_INPUT_TYPES.has(contentType)) {
|
|
189
|
+
return new Response('"url" parameter is valid but image type is not allowed', {
|
|
190
|
+
status: 400,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (contentType === SVG && !__IMAGES_ALLOW_SVG__) {
|
|
194
|
+
return new Response('"url" parameter is valid but image type is not allowed', {
|
|
195
|
+
status: 400,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return new Response(imageStream, {
|
|
199
|
+
headers: { "Content-Type": contentType },
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Parses a /cdn-cgi/image/ request URL.
|
|
204
|
+
*
|
|
205
|
+
* Extracts the image URL from the `/cdn-cgi/image/<options>/<image-url>` path format.
|
|
206
|
+
* Rejects protocol-relative URLs (`//...`). The cdn-cgi options are not parsed or
|
|
207
|
+
* validated as they are Cloudflare's concern.
|
|
208
|
+
*
|
|
209
|
+
* @param pathname The URL pathname (e.g. `/cdn-cgi/image/width=640,quality=75,format=auto/path/to/image.png`).
|
|
210
|
+
* @returns the parsed URL result or an error.
|
|
211
|
+
*/
|
|
212
|
+
export function parseCdnCgiImageRequest(pathname) {
|
|
213
|
+
const match = pathname.match(/^\/cdn-cgi\/image\/(?<options>[^/]+)\/(?<url>.+)$/);
|
|
214
|
+
if (match === null ||
|
|
215
|
+
// Valid URLs have at least one option
|
|
216
|
+
!match.groups?.options ||
|
|
217
|
+
!match.groups?.url) {
|
|
218
|
+
return { ok: false, message: "Invalid /cdn-cgi/image/ URL format" };
|
|
219
|
+
}
|
|
220
|
+
const imageUrl = match.groups.url;
|
|
221
|
+
// The regex separator consumes one `/`, so if imageUrl starts with `/`
|
|
222
|
+
// the original URL segment was protocol-relative (`//...`).
|
|
223
|
+
if (imageUrl.startsWith("/")) {
|
|
224
|
+
return { ok: false, message: '"url" parameter cannot be a protocol-relative URL (//)' };
|
|
225
|
+
}
|
|
226
|
+
// Resolve the image URL: it may be absolute (https://...) or relative.
|
|
227
|
+
let resolvedUrl;
|
|
228
|
+
if (imageUrl.match(/^https?:\/\//)) {
|
|
229
|
+
resolvedUrl = imageUrl;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// Relative URLs need a leading slash.
|
|
233
|
+
resolvedUrl = `/${imageUrl}`;
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
ok: true,
|
|
237
|
+
url: resolvedUrl,
|
|
238
|
+
static: false,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Reads the first 32 bytes of an image response to detect its content type.
|
|
243
|
+
*
|
|
244
|
+
* Tees the response body so the image stream can still be consumed after detection.
|
|
245
|
+
*
|
|
246
|
+
* @param imageResponse The image response whose body to read.
|
|
247
|
+
* @returns The detected content type and image stream, or an error Response if the header bytes
|
|
248
|
+
* could not be read.
|
|
249
|
+
*/
|
|
250
|
+
async function readImageHeader(imageResponse) {
|
|
251
|
+
// Note: imageResponse.body is non-null — callers check before calling.
|
|
252
|
+
const [contentTypeStream, imageStream] = imageResponse.body.tee();
|
|
253
|
+
const headerBytes = new Uint8Array(32);
|
|
254
|
+
const reader = contentTypeStream.getReader({ mode: "byob" });
|
|
255
|
+
const readResult = await reader.readAtLeast(32, headerBytes);
|
|
256
|
+
if (readResult.value === undefined) {
|
|
257
|
+
await imageResponse.body.cancel();
|
|
258
|
+
return new Response('"url" parameter is valid but upstream response is invalid', {
|
|
259
|
+
status: 400,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
const contentType = detectImageContentType(readResult.value);
|
|
263
|
+
return { contentType, imageStream };
|
|
264
|
+
}
|
|
156
265
|
/**
|
|
157
266
|
* Fetch call with max redirects and timeouts.
|
|
158
267
|
*
|
|
@@ -268,6 +377,9 @@ function parseImageRequest(requestURL, requestHeaders) {
|
|
|
268
377
|
/**
|
|
269
378
|
* Validates that there is exactly one "url" query parameter.
|
|
270
379
|
*
|
|
380
|
+
* Checks length, protocol-relative URLs, local/remote pattern matching, recursion, and protocol.
|
|
381
|
+
*
|
|
382
|
+
* @param requestURL The request URL containing the "url" query parameter.
|
|
271
383
|
* @returns the validated URL or an error result.
|
|
272
384
|
*/
|
|
273
385
|
function validateUrlQueryParameter(requestURL) {
|
|
@@ -287,7 +399,6 @@ function validateUrlQueryParameter(requestURL) {
|
|
|
287
399
|
};
|
|
288
400
|
return result;
|
|
289
401
|
}
|
|
290
|
-
// The url parameter value should be a valid URL or a valid relative URL.
|
|
291
402
|
const url = urls[0];
|
|
292
403
|
if (url.length > 3072) {
|
|
293
404
|
const result = {
|
|
@@ -515,6 +626,12 @@ const ICO = "image/x-icon";
|
|
|
515
626
|
const ICNS = "image/x-icns";
|
|
516
627
|
const TIFF = "image/tiff";
|
|
517
628
|
const BMP = "image/bmp";
|
|
629
|
+
/**
|
|
630
|
+
* Image content types supported as input by Cloudflare's cdn-cgi image transformation.
|
|
631
|
+
*
|
|
632
|
+
* @see https://developers.cloudflare.com/images/transform-images/#supported-input-formats
|
|
633
|
+
*/
|
|
634
|
+
const SUPPORTED_CDN_CGI_INPUT_TYPES = new Set([JPEG, PNG, GIF, WEBP, SVG, HEIC]);
|
|
518
635
|
/**
|
|
519
636
|
* Detects the content type by looking at the first few bytes of a file
|
|
520
637
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//@ts-expect-error: Will be resolved by wrangler build
|
|
2
|
-
import { handleImageRequest } from "./cloudflare/images.js";
|
|
2
|
+
import { handleCdnCgiImageRequest, handleImageRequest } from "./cloudflare/images.js";
|
|
3
3
|
//@ts-expect-error: Will be resolved by wrangler build
|
|
4
4
|
import { runWithCloudflareRequestContext } from "./cloudflare/init.js";
|
|
5
5
|
//@ts-expect-error: Will be resolved by wrangler build
|
|
@@ -23,14 +23,7 @@ export default {
|
|
|
23
23
|
// Serve images in development.
|
|
24
24
|
// Note: "/cdn-cgi/image/..." requests do not reach production workers.
|
|
25
25
|
if (url.pathname.startsWith("/cdn-cgi/image/")) {
|
|
26
|
-
|
|
27
|
-
if (m === null) {
|
|
28
|
-
return new Response("Not Found!", { status: 404 });
|
|
29
|
-
}
|
|
30
|
-
const imageUrl = m.groups.url;
|
|
31
|
-
return imageUrl.match(/^https?:\/\//)
|
|
32
|
-
? fetch(imageUrl, { cf: { cacheEverything: true } })
|
|
33
|
-
: env.ASSETS?.fetch(new URL(`/${imageUrl}`, url));
|
|
26
|
+
return handleCdnCgiImageRequest(url, env);
|
|
34
27
|
}
|
|
35
28
|
// Fallback for the Next default image loader.
|
|
36
29
|
if (url.pathname ===
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface Account {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Prompts the user to select a Cloudflare account from a list via an interactive CLI prompt.
|
|
7
|
+
*
|
|
8
|
+
* @param accounts - The list of Cloudflare accounts to choose from.
|
|
9
|
+
* @returns The ID of the selected account, or `undefined` if no selection was made.
|
|
10
|
+
*/
|
|
11
|
+
export declare function askAccountSelection(accounts: Account[]): Promise<string | undefined>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import Enquirer from "enquirer";
|
|
3
|
+
/**
|
|
4
|
+
* Prompts the user to select a Cloudflare account from a list via an interactive CLI prompt.
|
|
5
|
+
*
|
|
6
|
+
* @param accounts - The list of Cloudflare accounts to choose from.
|
|
7
|
+
* @returns The ID of the selected account, or `undefined` if no selection was made.
|
|
8
|
+
*/
|
|
9
|
+
export async function askAccountSelection(accounts) {
|
|
10
|
+
const questionName = randomUUID();
|
|
11
|
+
const enquirerAnswersObject = await Enquirer.prompt({
|
|
12
|
+
name: questionName,
|
|
13
|
+
message: "Select which Cloudflare account to use",
|
|
14
|
+
type: "select",
|
|
15
|
+
choices: accounts.map((account) => ({
|
|
16
|
+
name: account.id,
|
|
17
|
+
message: account.name,
|
|
18
|
+
})),
|
|
19
|
+
format: (accountId) => `${accounts.find(({ id }) => id === accountId)?.name ?? ""}`,
|
|
20
|
+
});
|
|
21
|
+
console.log("");
|
|
22
|
+
return enquirerAnswersObject[questionName];
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds the path to the OpenNext configuration file if it exists.
|
|
3
|
+
*
|
|
4
|
+
* @param appDir The directory to check for the open-next.config.ts file
|
|
5
|
+
* @returns The full path to open-next.config.ts if it exists, undefined otherwise
|
|
6
|
+
*/
|
|
7
|
+
export declare function findOpenNextConfig(appDir: string): string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Creates an `open-next.config.ts` file for the application.
|
|
10
|
+
*
|
|
11
|
+
* @param appDir The Next.js application root directory
|
|
12
|
+
* @param options.cache Whether to set up caching
|
|
13
|
+
* @returns The path to the created configuration file
|
|
14
|
+
*/
|
|
15
|
+
export declare function createOpenNextConfigFile(appDir: string, options: {
|
|
16
|
+
cache: boolean;
|
|
17
|
+
}): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { patchCode } from "@opennextjs/aws/build/patch/astCodePatcher.js";
|
|
4
|
+
import { getPackageTemplatesDirPath } from "../../utils/get-package-templates-dir-path.js";
|
|
5
|
+
/**
|
|
6
|
+
* Finds the path to the OpenNext configuration file if it exists.
|
|
7
|
+
*
|
|
8
|
+
* @param appDir The directory to check for the open-next.config.ts file
|
|
9
|
+
* @returns The full path to open-next.config.ts if it exists, undefined otherwise
|
|
10
|
+
*/
|
|
11
|
+
export function findOpenNextConfig(appDir) {
|
|
12
|
+
const openNextConfigPath = join(appDir, "open-next.config.ts");
|
|
13
|
+
if (existsSync(openNextConfigPath)) {
|
|
14
|
+
return openNextConfigPath;
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates an `open-next.config.ts` file for the application.
|
|
20
|
+
*
|
|
21
|
+
* @param appDir The Next.js application root directory
|
|
22
|
+
* @param options.cache Whether to set up caching
|
|
23
|
+
* @returns The path to the created configuration file
|
|
24
|
+
*/
|
|
25
|
+
export function createOpenNextConfigFile(appDir, options) {
|
|
26
|
+
const openNextConfigPath = join(appDir, "open-next.config.ts");
|
|
27
|
+
let content = readFileSync(join(getPackageTemplatesDirPath(), "open-next.config.ts"), "utf8");
|
|
28
|
+
if (!options.cache) {
|
|
29
|
+
content = patchCode(content, commentOutR2ImportRule);
|
|
30
|
+
content = patchCode(content, commentOutIncrementalCacheRule);
|
|
31
|
+
}
|
|
32
|
+
writeFileSync(openNextConfigPath, content);
|
|
33
|
+
return openNextConfigPath;
|
|
34
|
+
}
|
|
35
|
+
const commentOutR2ImportRule = `
|
|
36
|
+
rule:
|
|
37
|
+
pattern: import $ID from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
|
|
38
|
+
fix: |-
|
|
39
|
+
// import $ID from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
|
|
40
|
+
`;
|
|
41
|
+
const commentOutIncrementalCacheRule = `
|
|
42
|
+
rule:
|
|
43
|
+
pattern: '{ incrementalCache: $ID }'
|
|
44
|
+
fix: |-
|
|
45
|
+
{
|
|
46
|
+
// For best results consider enabling R2 caching
|
|
47
|
+
// See https://opennext.js.org/cloudflare/caching for more details
|
|
48
|
+
// incrementalCache: $ID
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the path to the Wrangler configuration file if it exists.
|
|
3
|
+
*
|
|
4
|
+
* @param appDir The directory to check for the Wrangler config file
|
|
5
|
+
* @returns The path to Wrangler config file if it exists, undefined otherwise
|
|
6
|
+
*/
|
|
7
|
+
export declare function findWranglerConfig(appDir: string): string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a wrangler.jsonc config file in the target directory for the project.
|
|
10
|
+
*
|
|
11
|
+
* If a wrangler.jsonc file already exists it will be overridden.
|
|
12
|
+
*
|
|
13
|
+
* The function attempts to create an R2 bucket for incremental cache. If bucket creation
|
|
14
|
+
* fails (e.g., user not authenticated or R2 not enabled), a configuration without caching
|
|
15
|
+
* will be created instead.
|
|
16
|
+
*
|
|
17
|
+
* @param projectDir The target directory for the project
|
|
18
|
+
* @param defaultCompatDate The default YYYY-MM-DD compatibility date to use in the config (used if fetching the latest workerd version date fails)
|
|
19
|
+
* @returns An object containing a `cachingEnabled` which indicates whether caching has been set up during the wrangler
|
|
20
|
+
* config file creation or not
|
|
21
|
+
*/
|
|
22
|
+
export declare function createWranglerConfigFile(projectDir: string, defaultCompatDate?: string): Promise<{
|
|
23
|
+
cachingEnabled: boolean;
|
|
24
|
+
}>;
|