@opennextjs/cloudflare 1.16.5 → 1.17.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 (54) hide show
  1. package/dist/cli/build/build.js +1 -1
  2. package/dist/cli/build/bundle-server.js +3 -1
  3. package/dist/cli/build/open-next/compile-env-files.js +1 -1
  4. package/dist/cli/build/open-next/createServerBundle.js +1 -1
  5. package/dist/cli/build/patches/plugins/dynamic-requires.js +1 -1
  6. package/dist/cli/build/patches/plugins/instrumentation.js +1 -1
  7. package/dist/cli/build/patches/plugins/load-manifest.js +1 -1
  8. package/dist/cli/build/patches/plugins/next-server.js +1 -1
  9. package/dist/cli/build/patches/plugins/route-module.js +1 -1
  10. package/dist/cli/build/patches/plugins/wrangler-external.js +1 -1
  11. package/dist/cli/build/utils/index.d.ts +0 -6
  12. package/dist/cli/build/utils/index.js +1 -6
  13. package/dist/cli/commands/build.js +2 -2
  14. package/dist/cli/commands/deploy.d.ts +1 -1
  15. package/dist/cli/commands/deploy.js +9 -4
  16. package/dist/cli/commands/migrate.js +16 -8
  17. package/dist/cli/commands/populate-cache.d.ts +2 -2
  18. package/dist/cli/commands/populate-cache.js +19 -7
  19. package/dist/cli/commands/preview.d.ts +1 -1
  20. package/dist/cli/commands/preview.js +9 -4
  21. package/dist/cli/commands/skew-protection.d.ts +1 -1
  22. package/dist/cli/commands/upload.d.ts +1 -1
  23. package/dist/cli/commands/upload.js +9 -4
  24. package/dist/cli/commands/{helpers.js → utils/helpers.js} +1 -1
  25. package/dist/cli/commands/utils/run-wrangler.d.ts +44 -0
  26. package/dist/cli/{utils → commands/utils}/run-wrangler.js +46 -11
  27. package/dist/cli/commands/{utils.d.ts → utils/utils.d.ts} +1 -11
  28. package/dist/cli/commands/{utils.js → utils/utils.js} +2 -24
  29. package/dist/cli/project-options.d.ts +1 -1
  30. package/dist/cli/utils/ask-account-selection.d.ts +12 -0
  31. package/dist/cli/utils/ask-account-selection.js +23 -0
  32. package/dist/cli/{build/utils → utils}/create-config-files.d.ts +1 -1
  33. package/dist/cli/{build/utils → utils}/create-config-files.js +4 -4
  34. package/dist/cli/utils/create-open-next-config.d.ts +17 -0
  35. package/dist/cli/utils/create-open-next-config.js +50 -0
  36. package/dist/cli/utils/create-wrangler-config.d.ts +24 -0
  37. package/dist/cli/utils/create-wrangler-config.js +244 -0
  38. package/dist/cli/utils/nextjs-support.d.ts +10 -0
  39. package/dist/cli/utils/nextjs-support.js +24 -0
  40. package/package.json +3 -2
  41. package/templates/open-next.config.ts +1 -1
  42. package/templates/wrangler.jsonc +2 -2
  43. package/dist/cli/utils/open-next-config.d.ts +0 -14
  44. package/dist/cli/utils/open-next-config.js +0 -27
  45. package/dist/cli/utils/run-wrangler.d.ts +0 -12
  46. package/dist/cli/utils/wrangler-config.d.ts +0 -15
  47. package/dist/cli/utils/wrangler-config.js +0 -63
  48. /package/dist/cli/{build → commands}/utils/files.d.ts +0 -0
  49. /package/dist/cli/{build → commands}/utils/files.js +0 -0
  50. /package/dist/cli/commands/{helpers.d.ts → utils/helpers.d.ts} +0 -0
  51. /package/dist/cli/{build/utils → utils}/extract-project-env-vars.d.ts +0 -0
  52. /package/dist/cli/{build/utils → utils}/extract-project-env-vars.js +0 -0
  53. /package/dist/cli/{build/utils → utils}/normalize-path.d.ts +0 -0
  54. /package/dist/cli/{build/utils → utils}/normalize-path.js +0 -0
@@ -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
+ }
@@ -1,4 +1,4 @@
1
- import type { ProjectOptions } from "../../project-options.js";
1
+ import type { ProjectOptions } from "../project-options.js";
2
2
  /**
3
3
  * Creates a `wrangler.jsonc` file for the user if a wrangler config file doesn't already exist,
4
4
  * but only after asking for the user's confirmation.
@@ -1,6 +1,6 @@
1
- import { askConfirmation } from "../../utils/ask-confirmation.js";
2
- import { createOpenNextConfigFile, findOpenNextConfig } from "../../utils/open-next-config.js";
3
- import { createWranglerConfigFile, findWranglerConfig } from "../../utils/wrangler-config.js";
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
4
  /**
5
5
  * Creates a `wrangler.jsonc` file for the user if a wrangler config file doesn't already exist,
6
6
  * but only after asking for the user's confirmation.
@@ -38,7 +38,7 @@ export async function createOpenNextConfigIfNotExistent(sourceDir) {
38
38
  if (!answer) {
39
39
  throw new Error("The `open-next.config.ts` file is required, aborting!");
40
40
  }
41
- return createOpenNextConfigFile(sourceDir);
41
+ return createOpenNextConfigFile(sourceDir, { cache: false });
42
42
  }
43
43
  return openNextConfigPath;
44
44
  }
@@ -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
+ }>;
@@ -0,0 +1,244 @@
1
+ import assert from "node:assert";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { findPackagerAndRoot } from "@opennextjs/aws/build/helper.js";
5
+ import Cloudflare from "cloudflare";
6
+ import { parse, stringify } from "comment-json";
7
+ import { getPackageTemplatesDirPath } from "../../utils/get-package-templates-dir-path.js";
8
+ import { runWrangler } from "../commands/utils/run-wrangler.js";
9
+ import { askAccountSelection } from "./ask-account-selection.js";
10
+ /**
11
+ * Gets the path to the Wrangler configuration file if it exists.
12
+ *
13
+ * @param appDir The directory to check for the Wrangler config file
14
+ * @returns The path to Wrangler config file if it exists, undefined otherwise
15
+ */
16
+ export function findWranglerConfig(appDir) {
17
+ const possibleExts = ["toml", "json", "jsonc"];
18
+ for (const ext of possibleExts) {
19
+ const path = join(appDir, `wrangler.${ext}`);
20
+ if (existsSync(path)) {
21
+ return path;
22
+ }
23
+ }
24
+ return undefined;
25
+ }
26
+ /**
27
+ * Creates a wrangler.jsonc config file in the target directory for the project.
28
+ *
29
+ * If a wrangler.jsonc file already exists it will be overridden.
30
+ *
31
+ * The function attempts to create an R2 bucket for incremental cache. If bucket creation
32
+ * fails (e.g., user not authenticated or R2 not enabled), a configuration without caching
33
+ * will be created instead.
34
+ *
35
+ * @param projectDir The target directory for the project
36
+ * @param defaultCompatDate The default YYYY-MM-DD compatibility date to use in the config (used if fetching the latest workerd version date fails)
37
+ * @returns An object containing a `cachingEnabled` which indicates whether caching has been set up during the wrangler
38
+ * config file creation or not
39
+ */
40
+ export async function createWranglerConfigFile(projectDir, defaultCompatDate = "2026-02-01") {
41
+ const workerName = getWorkerName(projectDir);
42
+ const compatibilityDate = (await getLatestCompatDate()) ?? defaultCompatDate;
43
+ const wranglerConfigStr = readFileSync(join(getPackageTemplatesDirPath(), "wrangler.jsonc"), "utf8")
44
+ .replaceAll("<WORKER_NAME>", workerName)
45
+ .replaceAll("<COMPATIBILITY_DATE>", compatibilityDate);
46
+ const wranglerConfig = parse(wranglerConfigStr);
47
+ assert(Array.isArray(wranglerConfig.r2_buckets));
48
+ assert(wranglerConfig.r2_buckets[0] != null && typeof wranglerConfig.r2_buckets[0] === "object");
49
+ assert("bucket_name" in wranglerConfig.r2_buckets[0] &&
50
+ typeof wranglerConfig.r2_buckets[0].bucket_name === "string");
51
+ const bucketName = wranglerConfig.r2_buckets[0].bucket_name;
52
+ const { success: cachingEnabled } = await maybeCreateR2Bucket(projectDir, bucketName);
53
+ if (!cachingEnabled) {
54
+ delete wranglerConfig.r2_buckets;
55
+ }
56
+ writeFileSync(join(projectDir, "wrangler.jsonc"), stringify(wranglerConfig, null, "\t"));
57
+ return { cachingEnabled };
58
+ }
59
+ /**
60
+ * Gets a valid worker name from the project's package.json name, falling back to `app-name`
61
+ * in case the name could not be detected.
62
+ *
63
+ * @param projectDir The project directory containing the package.json file
64
+ * @returns A valid worker name suitable for a Cloudflare Worker
65
+ */
66
+ function getWorkerName(projectDir) {
67
+ const appName = getNameFromPackageJson(projectDir) ?? "app-name";
68
+ return (appName
69
+ .toLowerCase()
70
+ // Remove org prefix if present (e.g., "@org/my-app" -> "my-app")
71
+ .replace(/^@[^/]+\//, "")
72
+ .replaceAll("_", "-")
73
+ .replace(/[^a-z0-9-]/g, ""));
74
+ }
75
+ /**
76
+ * Reads the `name` field from the `package.json` in the given directory.
77
+ *
78
+ * @param sourceDir - The directory containing the `package.json` file.
79
+ * @returns The package name if found, `undefined` otherwise.
80
+ */
81
+ function getNameFromPackageJson(sourceDir) {
82
+ try {
83
+ const packageJsonStr = readFileSync(join(sourceDir, "package.json"), "utf8");
84
+ const packageJson = JSON.parse(packageJsonStr);
85
+ if (typeof packageJson.name === "string")
86
+ return packageJson.name;
87
+ }
88
+ catch {
89
+ /* empty */
90
+ }
91
+ }
92
+ /**
93
+ * Fetches the latest compatibility date from the npm registry based on the latest `workerd` version.
94
+ *
95
+ * The workerd version format is `major.yyyymmdd.patch`. The date portion is extracted and formatted
96
+ * as `YYYY-MM-DD`. If the extracted date is in the future, today's date is returned instead.
97
+ *
98
+ * @returns The compatibility date as a `YYYY-MM-DD` string, or `undefined` if the fetch or parsing fails.
99
+ */
100
+ async function getLatestCompatDate() {
101
+ try {
102
+ const resp = await fetch(`https://registry.npmjs.org/workerd`);
103
+ const latestWorkerdVersion = (await resp.json())["dist-tags"].latest;
104
+ // The format of the workerd version is `major.yyyymmdd.patch`.
105
+ const match = latestWorkerdVersion.match(/\d+\.(\d{4})(\d{2})(\d{2})\.\d+/);
106
+ if (match) {
107
+ const [, year, month, day] = match;
108
+ const compatDate = `${year}-${month}-${day}`;
109
+ const currentDate = new Date().toISOString().slice(0, 10);
110
+ return compatDate < currentDate ? compatDate : currentDate;
111
+ }
112
+ }
113
+ catch {
114
+ /* empty */
115
+ }
116
+ }
117
+ /**
118
+ * Gets the authentication credentials for Cloudflare API calls.
119
+ *
120
+ * Uses `wrangler auth token --json` which checks the following sources in order:
121
+ * 1. CLOUDFLARE_API_TOKEN environment variable
122
+ * 2. CLOUDFLARE_API_KEY + CLOUDFLARE_EMAIL environment variables
123
+ * 3. OAuth token from `wrangler login`
124
+ *
125
+ * @param options The build options containing packager and monorepo root
126
+ * @returns The auth credentials if available, undefined otherwise
127
+ */
128
+ function getAuthCredentials(options) {
129
+ const result = runWrangler(options, ["auth", "token", "--json"], { logging: "none" });
130
+ if (!result.success) {
131
+ return undefined;
132
+ }
133
+ try {
134
+ const json = JSON.parse(result.stdout);
135
+ if (json.type === "api_key") {
136
+ return { type: "api_key", apiKey: json.key, apiEmail: json.email };
137
+ }
138
+ // Both "oauth" and "api_token" types have a token field
139
+ if (json.token) {
140
+ return { type: "token", token: json.token };
141
+ }
142
+ }
143
+ catch {
144
+ /* empty */
145
+ }
146
+ return undefined;
147
+ }
148
+ /**
149
+ * Gets the account ID for Cloudflare API calls.
150
+ *
151
+ * Tries the following sources in order:
152
+ * 1. CLOUDFLARE_ACCOUNT_ID or CF_ACCOUNT_ID environment variable
153
+ * 2. List accounts using the SDK and return the first one
154
+ *
155
+ * @param client The Cloudflare SDK client
156
+ * @returns The account ID if available, undefined otherwise
157
+ */
158
+ async function getAccountId(client) {
159
+ if (process.env.CLOUDFLARE_ACCOUNT_ID || process.env.CF_ACCOUNT_ID) {
160
+ return process.env.CLOUDFLARE_ACCOUNT_ID || process.env.CF_ACCOUNT_ID;
161
+ }
162
+ try {
163
+ const accountsList = await client.accounts.list();
164
+ const accounts = [];
165
+ for await (const account of accountsList) {
166
+ accounts.push({ id: account.id, name: account.name });
167
+ }
168
+ if (accounts.length === 0) {
169
+ return undefined;
170
+ }
171
+ if (accounts.length === 1 && accounts[0]) {
172
+ return accounts[0].id;
173
+ }
174
+ return await askAccountSelection(accounts);
175
+ }
176
+ catch {
177
+ /* empty */
178
+ }
179
+ return undefined;
180
+ }
181
+ /**
182
+ * Attempts to log in to Cloudflare via wrangler.
183
+ *
184
+ * @param options The build options containing packager and monorepo root
185
+ * @returns true if login was successful, false otherwise
186
+ */
187
+ function wranglerLogin(options) {
188
+ const result = runWrangler(options, ["login"], { logging: "all" });
189
+ return result.success;
190
+ }
191
+ /**
192
+ * Creates an R2 bucket.
193
+ *
194
+ * If no auth credentials are available, falls back to wrangler login for OAuth authentication.
195
+ *
196
+ * @param projectDir The project directory to detect the package manager
197
+ * @param bucketName The name of the R2 bucket to create
198
+ * @returns An object indicating success with the bucket name, or failure
199
+ */
200
+ async function maybeCreateR2Bucket(projectDir, bucketName) {
201
+ try {
202
+ const { packager, root: monorepoRoot } = findPackagerAndRoot(projectDir);
203
+ const options = { packager, monorepoRoot };
204
+ let authCredentials = getAuthCredentials(options);
205
+ // If no credentials available, fall back to wrangler login
206
+ if (!authCredentials) {
207
+ const loginSuccess = wranglerLogin(options);
208
+ if (!loginSuccess) {
209
+ return { success: false };
210
+ }
211
+ // Get credentials after login
212
+ authCredentials = getAuthCredentials(options);
213
+ if (!authCredentials) {
214
+ return { success: false };
215
+ }
216
+ }
217
+ const client = authCredentials.type === "api_key"
218
+ ? new Cloudflare({ apiKey: authCredentials.apiKey, apiEmail: authCredentials.apiEmail })
219
+ : new Cloudflare({ apiToken: authCredentials.token });
220
+ const accountId = await getAccountId(client);
221
+ if (!accountId) {
222
+ return { success: false };
223
+ }
224
+ // Check if bucket already exists
225
+ try {
226
+ await client.r2.buckets.get(bucketName, { account_id: accountId });
227
+ // Bucket exists
228
+ return { success: true, bucketName };
229
+ }
230
+ catch (error) {
231
+ if (!(error instanceof Cloudflare.NotFoundError)) {
232
+ return { success: false };
233
+ }
234
+ }
235
+ await client.r2.buckets.create({
236
+ account_id: accountId,
237
+ name: bucketName,
238
+ });
239
+ return { success: true, bucketName };
240
+ }
241
+ catch {
242
+ return { success: false };
243
+ }
244
+ }
@@ -0,0 +1,10 @@
1
+ import * as buildHelper from "@opennextjs/aws/build/helper.js";
2
+ /**
3
+ * Validates that the Next.js version is supported and checks wrangler compatibility.
4
+ *
5
+ * Note: this function assumes that wrangler is installed.
6
+ *
7
+ * @param options.nextVersion The detected Next.js version string
8
+ * @throws {Error} If the Next.js version is unsupported
9
+ */
10
+ export declare function ensureNextjsVersionSupported({ nextVersion, }: Pick<buildHelper.BuildOptions, "nextVersion">): Promise<void>;
@@ -0,0 +1,24 @@
1
+ import * as buildHelper from "@opennextjs/aws/build/helper.js";
2
+ import logger from "@opennextjs/aws/logger.js";
3
+ /**
4
+ * Validates that the Next.js version is supported and checks wrangler compatibility.
5
+ *
6
+ * Note: this function assumes that wrangler is installed.
7
+ *
8
+ * @param options.nextVersion The detected Next.js version string
9
+ * @throws {Error} If the Next.js version is unsupported
10
+ */
11
+ export async function ensureNextjsVersionSupported({ nextVersion, }) {
12
+ if (buildHelper.compareSemver(nextVersion, "<", "14.2.0")) {
13
+ throw new Error("Next.js version unsupported, please upgrade to version 14.2 or greater.");
14
+ }
15
+ const { default: { version: wranglerVersion }, } = await import("wrangler/package.json", { with: { type: "json" } });
16
+ // We need a version of workerd that has a fix for setImmediate for Next.js 16.1+
17
+ // See:
18
+ // - https://github.com/cloudflare/workerd/pull/5869
19
+ // - https://github.com/opennextjs/opennextjs-cloudflare/issues/1049
20
+ if (buildHelper.compareSemver(nextVersion, ">=", "16.1.0") &&
21
+ buildHelper.compareSemver(wranglerVersion, "<", "4.59.2")) {
22
+ logger.warn(`Next.js 16.1+ requires wrangler 4.59.2 or greater (${wranglerVersion} detected).`);
23
+ }
24
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@opennextjs/cloudflare",
3
3
  "description": "Cloudflare builder for next apps",
4
- "version": "1.16.5",
4
+ "version": "1.17.0",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "opennextjs-cloudflare": "dist/cli/index.js"
@@ -48,6 +48,7 @@
48
48
  "cloudflare": "^4.4.1",
49
49
  "enquirer": "^2.4.1",
50
50
  "glob": "^12.0.0",
51
+ "comment-json": "^4.5.1",
51
52
  "ts-tqdm": "^0.8.6",
52
53
  "yargs": "^18.0.0"
53
54
  },
@@ -75,7 +76,7 @@
75
76
  "vitest": "^2.1.1"
76
77
  },
77
78
  "peerDependencies": {
78
- "wrangler": "^4.59.2",
79
+ "wrangler": "^4.65.0",
79
80
  "next": "~15.0.8 || ~15.1.12 || ~15.2.9 || ~15.3.9 || ~15.4.11 || ~15.5.10 || ~16.0.11 || ^16.1.5"
80
81
  },
81
82
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  // default open-next.config.ts file created by @opennextjs/cloudflare
2
- import { defineCloudflareConfig } from "@opennextjs/cloudflare/config";
2
+ import { defineCloudflareConfig } from "@opennextjs/cloudflare";
3
3
  import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
4
4
 
5
5
  export default defineCloudflareConfig({
@@ -2,7 +2,7 @@
2
2
  "$schema": "node_modules/wrangler/config-schema.json",
3
3
  "main": ".open-next/worker.js",
4
4
  "name": "<WORKER_NAME>",
5
- "compatibility_date": "2025-12-01",
5
+ "compatibility_date": "<COMPATIBILITY_DATE>",
6
6
  "compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
7
7
  "assets": {
8
8
  "directory": ".open-next/assets",
@@ -24,7 +24,7 @@
24
24
  // Create the bucket before deploying
25
25
  // You can change the bucket name if you want
26
26
  // See https://developers.cloudflare.com/workers/wrangler/commands/#r2-bucket-create
27
- "bucket_name": "cache"
27
+ "bucket_name": "<WORKER_NAME>-opennext-cache"
28
28
  }
29
29
  ],
30
30
  "images": {
@@ -1,14 +0,0 @@
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 a `open-next.config.ts` file in the target directory for the project.
10
- *
11
- * @param appDir The Next application root
12
- * @return The path to the created source file
13
- */
14
- export declare function createOpenNextConfigFile(appDir: string): Promise<string>;
@@ -1,27 +0,0 @@
1
- import { cpSync, existsSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { getPackageTemplatesDirPath } from "../../utils/get-package-templates-dir-path.js";
4
- /**
5
- * Finds the path to the OpenNext configuration file if it exists.
6
- *
7
- * @param appDir The directory to check for the open-next.config.ts file
8
- * @returns The full path to open-next.config.ts if it exists, undefined otherwise
9
- */
10
- export function findOpenNextConfig(appDir) {
11
- const openNextConfigPath = join(appDir, "open-next.config.ts");
12
- if (existsSync(openNextConfigPath)) {
13
- return openNextConfigPath;
14
- }
15
- return undefined;
16
- }
17
- /**
18
- * Creates a `open-next.config.ts` file in the target directory for the project.
19
- *
20
- * @param appDir The Next application root
21
- * @return The path to the created source file
22
- */
23
- export async function createOpenNextConfigFile(appDir) {
24
- const openNextConfigPath = join(appDir, "open-next.config.ts");
25
- cpSync(join(getPackageTemplatesDirPath(), "open-next.config.ts"), openNextConfigPath);
26
- return openNextConfigPath;
27
- }
@@ -1,12 +0,0 @@
1
- import type { BuildOptions } from "@opennextjs/aws/build/helper.js";
2
- export type WranglerTarget = "local" | "remote";
3
- type WranglerOptions = {
4
- target?: WranglerTarget;
5
- environment?: string;
6
- configPath?: string;
7
- logging?: "all" | "error";
8
- env?: Record<string, string>;
9
- };
10
- export declare function runWrangler(options: BuildOptions, args: string[], wranglerOpts?: WranglerOptions): void;
11
- export declare function isWranglerTarget(v: string | undefined): v is WranglerTarget;
12
- export {};
@@ -1,15 +0,0 @@
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
- * @param projectDir The target directory for the project
14
- */
15
- export declare function createWranglerConfigFile(projectDir: string): Promise<void>;
@@ -1,63 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { getPackageTemplatesDirPath } from "../../utils/get-package-templates-dir-path.js";
4
- /**
5
- * Gets the path to the Wrangler configuration file if it exists.
6
- *
7
- * @param appDir The directory to check for the Wrangler config file
8
- * @returns The path to Wrangler config file if it exists, undefined otherwise
9
- */
10
- export function findWranglerConfig(appDir) {
11
- const possibleExts = ["toml", "json", "jsonc"];
12
- for (const ext of possibleExts) {
13
- const path = join(appDir, `wrangler.${ext}`);
14
- if (existsSync(path)) {
15
- return path;
16
- }
17
- }
18
- return undefined;
19
- }
20
- /**
21
- * Creates a wrangler.jsonc config file in the target directory for the project.
22
- *
23
- * If a wrangler.jsonc file already exists it will be overridden.
24
- *
25
- * @param projectDir The target directory for the project
26
- */
27
- export async function createWranglerConfigFile(projectDir) {
28
- let wranglerConfig = readFileSync(join(getPackageTemplatesDirPath(), "wrangler.jsonc"), "utf8");
29
- const appName = getAppNameFromPackageJson(projectDir) ?? "app-name";
30
- wranglerConfig = wranglerConfig.replaceAll('"<WORKER_NAME>"', JSON.stringify(appName.replaceAll("_", "-")));
31
- const compatDate = await getLatestCompatDate();
32
- if (compatDate) {
33
- wranglerConfig = wranglerConfig.replace(/"compatibility_date": "\d{4}-\d{2}-\d{2}"/, `"compatibility_date": ${JSON.stringify(compatDate)}`);
34
- }
35
- writeFileSync(join(projectDir, "wrangler.jsonc"), wranglerConfig);
36
- }
37
- function getAppNameFromPackageJson(sourceDir) {
38
- try {
39
- const packageJsonStr = readFileSync(join(sourceDir, "package.json"), "utf8");
40
- const packageJson = JSON.parse(packageJsonStr);
41
- if (typeof packageJson.name === "string")
42
- return packageJson.name;
43
- }
44
- catch {
45
- /* empty */
46
- }
47
- }
48
- async function getLatestCompatDate() {
49
- try {
50
- const resp = await fetch(`https://registry.npmjs.org/workerd`);
51
- const latestWorkerdVersion = (await resp.json())["dist-tags"].latest;
52
- // The format of the workerd version is `major.yyyymmdd.patch`.
53
- const match = latestWorkerdVersion.match(/\d+\.(\d{4})(\d{2})(\d{2})\.\d+/);
54
- if (match) {
55
- const [, year, month, date] = match;
56
- const compatDate = `${year}-${month}-${date}`;
57
- return compatDate;
58
- }
59
- }
60
- catch {
61
- /* empty */
62
- }
63
- }
File without changes
File without changes