@opennextjs/cloudflare 1.17.0 → 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/commands/build.d.ts +13 -0
- package/dist/cli/commands/build.js +15 -3
- package/dist/cli/commands/utils/utils.d.ts +5 -1
- package/dist/cli/commands/utils/utils.js +13 -3
- 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/package.json +1 -1
- package/dist/cli/utils/create-config-files.d.ts +0 -19
- package/dist/cli/utils/create-config-files.js +0 -44
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import type yargs from "yargs";
|
|
2
|
+
import type { WithWranglerArgs } from "./utils/utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* Implementation of the `opennextjs-cloudflare build` command.
|
|
5
|
+
*
|
|
6
|
+
* @param args
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildCommand(args: WithWranglerArgs<{
|
|
9
|
+
skipNextBuild: boolean;
|
|
10
|
+
noMinify: boolean;
|
|
11
|
+
skipWranglerConfigCheck: boolean;
|
|
12
|
+
openNextConfigPath: string | undefined;
|
|
13
|
+
dangerouslyUseUnsupportedNextVersion: boolean;
|
|
14
|
+
}>): Promise<void>;
|
|
2
15
|
/**
|
|
3
16
|
* Add the `build` command to yargs configuration.
|
|
4
17
|
*
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import logger from "@opennextjs/aws/logger.js";
|
|
1
2
|
import { build as buildImpl } from "../build/build.js";
|
|
2
|
-
import {
|
|
3
|
+
import { askConfirmation } from "../utils/ask-confirmation.js";
|
|
4
|
+
import { createWranglerConfigFile, findWranglerConfig } from "../utils/create-wrangler-config.js";
|
|
3
5
|
import { compileConfig, getNormalizedOptions, nextAppDir, printHeaders, readWranglerConfig, withWranglerOptions, withWranglerPassthroughArgs, } from "./utils/utils.js";
|
|
4
6
|
/**
|
|
5
7
|
* Implementation of the `opennextjs-cloudflare build` command.
|
|
6
8
|
*
|
|
7
9
|
* @param args
|
|
8
10
|
*/
|
|
9
|
-
async function buildCommand(args) {
|
|
11
|
+
export async function buildCommand(args) {
|
|
10
12
|
printHeaders("build");
|
|
11
13
|
const { config, buildDir } = await compileConfig(args.openNextConfigPath);
|
|
12
14
|
const options = getNormalizedOptions(config, buildDir);
|
|
@@ -15,7 +17,17 @@ async function buildCommand(args) {
|
|
|
15
17
|
// Note: We don't ask when a custom config file is specified via `--config`
|
|
16
18
|
// nor when `--skipWranglerConfigCheck` is used.
|
|
17
19
|
if (!projectOpts.wranglerConfigPath && !args.skipWranglerConfigCheck) {
|
|
18
|
-
|
|
20
|
+
if (!findWranglerConfig(projectOpts.sourceDir)) {
|
|
21
|
+
const confirmCreate = "No `wrangler.(toml|json|jsonc)` config file found, do you want to create one?";
|
|
22
|
+
if (await askConfirmation(confirmCreate)) {
|
|
23
|
+
await createWranglerConfigFile(projectOpts.sourceDir);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
logger.warn(`No Wrangler config file created
|
|
27
|
+
|
|
28
|
+
(to avoid this check use the \`--skipWranglerConfigCheck\` flag or set a \`SKIP_WRANGLER_CONFIG_CHECK\` environment variable to \`yes\`)`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
19
31
|
}
|
|
20
32
|
const wranglerConfig = await readWranglerConfig(args);
|
|
21
33
|
await buildImpl(options, config, projectOpts, wranglerConfig, args.dangerouslyUseUnsupportedNextVersion);
|
|
@@ -20,8 +20,12 @@ export declare function printHeaders(command: string): void;
|
|
|
20
20
|
*
|
|
21
21
|
* When users specify a custom config file but it doesn't exist, we throw an Error.
|
|
22
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
|
+
*
|
|
23
26
|
* @param configPath Optional path to the config file. Absolute or relative to cwd.
|
|
24
|
-
* @returns OpenNext config.
|
|
27
|
+
* @returns The compiled OpenNext config and the build directory.
|
|
28
|
+
*
|
|
25
29
|
*/
|
|
26
30
|
export declare function compileConfig(configPath: string | undefined): Promise<{
|
|
27
31
|
config: import("@opennextjs/aws/types/open-next.js").OpenNextConfig;
|
|
@@ -8,7 +8,8 @@ import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.j
|
|
|
8
8
|
import logger from "@opennextjs/aws/logger.js";
|
|
9
9
|
import { unstable_readConfig } from "wrangler";
|
|
10
10
|
import { ensureCloudflareConfig } from "../../build/utils/ensure-cf-config.js";
|
|
11
|
-
import {
|
|
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.
|
|
@@ -27,15 +28,24 @@ export function printHeaders(command) {
|
|
|
27
28
|
*
|
|
28
29
|
* When users specify a custom config file but it doesn't exist, we throw an Error.
|
|
29
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
|
+
*
|
|
30
34
|
* @param configPath Optional path to the config file. Absolute or relative to cwd.
|
|
31
|
-
* @returns OpenNext config.
|
|
35
|
+
* @returns The compiled OpenNext config and the build directory.
|
|
36
|
+
*
|
|
32
37
|
*/
|
|
33
38
|
export async function compileConfig(configPath) {
|
|
34
39
|
if (configPath && !existsSync(configPath)) {
|
|
35
40
|
throw new Error(`Custom config file not found at ${configPath}`);
|
|
36
41
|
}
|
|
42
|
+
configPath ??= findOpenNextConfig(nextAppDir);
|
|
37
43
|
if (!configPath) {
|
|
38
|
-
|
|
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 });
|
|
39
49
|
}
|
|
40
50
|
const { config, buildDir } = await compileOpenNextConfig(configPath, { compileEdge: true });
|
|
41
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 ===
|
package/package.json
CHANGED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { ProjectOptions } from "../project-options.js";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a `wrangler.jsonc` file for the user if a wrangler config file doesn't already exist,
|
|
4
|
-
* but only after asking for the user's confirmation.
|
|
5
|
-
*
|
|
6
|
-
* If the user refuses a warning is shown (which offers ways to opt out of this check to the user).
|
|
7
|
-
*
|
|
8
|
-
* @param projectOpts The options for the project
|
|
9
|
-
*/
|
|
10
|
-
export declare function createWranglerConfigIfNonExistent(projectOpts: ProjectOptions): Promise<void>;
|
|
11
|
-
/**
|
|
12
|
-
* Creates a `open-next.config.ts` file for the user if it doesn't exist, but only after asking for the user's confirmation.
|
|
13
|
-
*
|
|
14
|
-
* If the user refuses an error is thrown (since the file is mandatory).
|
|
15
|
-
*
|
|
16
|
-
* @param sourceDir The source directory for the project
|
|
17
|
-
* @return The path to the created source file
|
|
18
|
-
*/
|
|
19
|
-
export declare function createOpenNextConfigIfNotExistent(sourceDir: string): Promise<string>;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { askConfirmation } from "./ask-confirmation.js";
|
|
2
|
-
import { createOpenNextConfigFile, findOpenNextConfig } from "./create-open-next-config.js";
|
|
3
|
-
import { createWranglerConfigFile, findWranglerConfig } from "./create-wrangler-config.js";
|
|
4
|
-
/**
|
|
5
|
-
* Creates a `wrangler.jsonc` file for the user if a wrangler config file doesn't already exist,
|
|
6
|
-
* but only after asking for the user's confirmation.
|
|
7
|
-
*
|
|
8
|
-
* If the user refuses a warning is shown (which offers ways to opt out of this check to the user).
|
|
9
|
-
*
|
|
10
|
-
* @param projectOpts The options for the project
|
|
11
|
-
*/
|
|
12
|
-
export async function createWranglerConfigIfNonExistent(projectOpts) {
|
|
13
|
-
const wranglerConfigFileExists = Boolean(findWranglerConfig(projectOpts.sourceDir));
|
|
14
|
-
if (wranglerConfigFileExists) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
const answer = await askConfirmation("No `wrangler.(toml|json|jsonc)` config file found, do you want to create one?");
|
|
18
|
-
if (!answer) {
|
|
19
|
-
console.warn("No Wrangler config file created" +
|
|
20
|
-
"\n" +
|
|
21
|
-
"(to avoid this check use the `--skipWranglerConfigCheck` flag or set a `SKIP_WRANGLER_CONFIG_CHECK` environment variable to `yes`)");
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
await createWranglerConfigFile(projectOpts.sourceDir);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Creates a `open-next.config.ts` file for the user if it doesn't exist, but only after asking for the user's confirmation.
|
|
28
|
-
*
|
|
29
|
-
* If the user refuses an error is thrown (since the file is mandatory).
|
|
30
|
-
*
|
|
31
|
-
* @param sourceDir The source directory for the project
|
|
32
|
-
* @return The path to the created source file
|
|
33
|
-
*/
|
|
34
|
-
export async function createOpenNextConfigIfNotExistent(sourceDir) {
|
|
35
|
-
const openNextConfigPath = findOpenNextConfig(sourceDir);
|
|
36
|
-
if (!openNextConfigPath) {
|
|
37
|
-
const answer = await askConfirmation("Missing required `open-next.config.ts` file, do you want to create one?");
|
|
38
|
-
if (!answer) {
|
|
39
|
-
throw new Error("The `open-next.config.ts` file is required, aborting!");
|
|
40
|
-
}
|
|
41
|
-
return createOpenNextConfigFile(sourceDir, { cache: false });
|
|
42
|
-
}
|
|
43
|
-
return openNextConfigPath;
|
|
44
|
-
}
|