@opennextjs/cloudflare 1.6.2 → 1.6.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.
@@ -63,7 +63,7 @@ export async function build(options, config, projectOpts, wranglerConfig) {
63
63
  }
64
64
  await createServerBundle(options);
65
65
  await compileDurableObjects(options);
66
- await bundleServer(options);
66
+ await bundleServer(options, projectOpts);
67
67
  if (!projectOpts.skipWranglerConfigCheck) {
68
68
  await createWranglerConfigIfNotExistent(projectOpts);
69
69
  }
@@ -1,8 +1,9 @@
1
1
  import { type BuildOptions } from "@opennextjs/aws/build/helper.js";
2
+ import type { ProjectOptions } from "../project-options.js";
2
3
  /**
3
4
  * Bundle the Open Next server.
4
5
  */
5
- export declare function bundleServer(buildOpts: BuildOptions): Promise<void>;
6
+ export declare function bundleServer(buildOpts: BuildOptions, projectOpts: ProjectOptions): Promise<void>;
6
7
  /**
7
8
  * This function apply updates to the bundled code.
8
9
  */
@@ -39,7 +39,7 @@ const optionalDependencies = [
39
39
  /**
40
40
  * Bundle the Open Next server.
41
41
  */
42
- export async function bundleServer(buildOpts) {
42
+ export async function bundleServer(buildOpts, projectOpts) {
43
43
  copyPackageCliFiles(packageDistDir, buildOpts);
44
44
  const { appPath, outputDir, monorepoRoot, debug } = buildOpts;
45
45
  const baseManifestPath = path.join(outputDir, "server-functions/default", getPackagePath(buildOpts), ".next");
@@ -60,9 +60,9 @@ export async function bundleServer(buildOpts) {
60
60
  format: "esm",
61
61
  target: "esnext",
62
62
  // Minify code as much as possible but stay safe by not renaming identifiers
63
- minifyWhitespace: !debug,
63
+ minifyWhitespace: projectOpts.minify && !debug,
64
64
  minifyIdentifiers: false,
65
- minifySyntax: !debug,
65
+ minifySyntax: projectOpts.minify && !debug,
66
66
  legalComments: "none",
67
67
  metafile: true,
68
68
  // Next traces files using the default conditions from `nft` (`node`, `require`, `import` and `default`)
@@ -37,22 +37,18 @@ function getRequires(idVariable, files, serverDir) {
37
37
  export function inlineDynamicRequires(updater, buildOpts) {
38
38
  updater.updateContent("inline-node-module-loader", [
39
39
  {
40
- field: {
41
- filter: getCrossPlatformPathRegex(String.raw `/module-loader/node-module-loader\.js$`, {
42
- escape: false,
43
- }),
44
- contentFilter: /class NodeModuleLoader {/,
45
- callback: async ({ contents }) => patchCode(contents, await getNodeModuleLoaderRule(buildOpts)),
46
- },
40
+ filter: getCrossPlatformPathRegex(String.raw `/module-loader/node-module-loader\.js$`, {
41
+ escape: false,
42
+ }),
43
+ contentFilter: /class NodeModuleLoader {/,
44
+ callback: async ({ contents }) => patchCode(contents, await getNodeModuleLoaderRule(buildOpts)),
47
45
  },
48
46
  ]);
49
47
  updater.updateContent("inline-require-page", [
50
48
  {
51
- field: {
52
- filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/require\.js$`, { escape: false }),
53
- contentFilter: /function requirePage\(/,
54
- callback: async ({ contents }) => patchCode(contents, await getRequirePageRule(buildOpts)),
55
- },
49
+ filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/require\.js$`, { escape: false }),
50
+ contentFilter: /function requirePage\(/,
51
+ callback: async ({ contents }) => patchCode(contents, await getRequirePageRule(buildOpts)),
56
52
  },
57
53
  ]);
58
54
  return { name: "inline-dynamic-requires", setup() { } };
@@ -9,11 +9,9 @@ import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
9
9
  export function inlineFindDir(updater, buildOpts) {
10
10
  return updater.updateContent("inline-find-dir", [
11
11
  {
12
- field: {
13
- filter: getCrossPlatformPathRegex(String.raw `/next/dist/lib/find-pages-dir\.js$`, { escape: false }),
14
- contentFilter: /function findDir\(/,
15
- callback: async ({ contents }) => patchCode(contents, await getRule(buildOpts)),
16
- },
12
+ filter: getCrossPlatformPathRegex(String.raw `/next/dist/lib/find-pages-dir\.js$`, { escape: false }),
13
+ contentFilter: /function findDir\(/,
14
+ callback: async ({ contents }) => patchCode(contents, await getRule(buildOpts)),
17
15
  },
18
16
  ]);
19
17
  }
@@ -8,31 +8,25 @@ export function patchInstrumentation(updater, buildOpts) {
8
8
  const builtInstrumentationPath = getBuiltInstrumentationPath(buildOpts);
9
9
  updater.updateContent("patch-instrumentation-next15-4", [
10
10
  {
11
- field: {
12
- filter: getCrossPlatformPathRegex(String.raw `/server/lib/router-utils/instrumentation-globals.external\.js$`, {
13
- escape: false,
14
- }),
15
- contentFilter: /getInstrumentationModule\(/,
16
- callback: ({ contents }) => patchCode(contents, getNext154Rule(builtInstrumentationPath)),
17
- },
11
+ filter: getCrossPlatformPathRegex(String.raw `/server/lib/router-utils/instrumentation-globals.external\.js$`, {
12
+ escape: false,
13
+ }),
14
+ contentFilter: /getInstrumentationModule\(/,
15
+ callback: ({ contents }) => patchCode(contents, getNext154Rule(builtInstrumentationPath)),
18
16
  },
19
17
  ]);
20
18
  updater.updateContent("patch-instrumentation-next15", [
21
19
  {
22
- field: {
23
- filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
24
- contentFilter: /async loadInstrumentationModule\(/,
25
- callback: ({ contents }) => patchCode(contents, getNext15Rule(builtInstrumentationPath)),
26
- },
20
+ filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
21
+ contentFilter: /async loadInstrumentationModule\(/,
22
+ callback: ({ contents }) => patchCode(contents, getNext15Rule(builtInstrumentationPath)),
27
23
  },
28
24
  ]);
29
25
  updater.updateContent("patch-instrumentation-next14", [
30
26
  {
31
- field: {
32
- filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
33
- contentFilter: /async prepareImpl\(/,
34
- callback: ({ contents }) => patchCode(contents, getNext14Rule(builtInstrumentationPath)),
35
- },
27
+ filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
28
+ contentFilter: /async prepareImpl\(/,
29
+ callback: ({ contents }) => patchCode(contents, getNext14Rule(builtInstrumentationPath)),
36
30
  },
37
31
  ]);
38
32
  return {
@@ -13,16 +13,14 @@ import { normalizePath } from "../../utils/normalize-path.js";
13
13
  export function inlineLoadManifest(updater, buildOpts) {
14
14
  return updater.updateContent("inline-load-manifest", [
15
15
  {
16
- field: {
17
- filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/load-manifest(\.external)?\.js$`, {
18
- escape: false,
19
- }),
20
- contentFilter: /function loadManifest\(/,
21
- callback: async ({ contents }) => {
22
- contents = await patchCode(contents, await getLoadManifestRule(buildOpts));
23
- contents = await patchCode(contents, await getEvalManifestRule(buildOpts));
24
- return contents;
25
- },
16
+ filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/load-manifest(\.external)?\.js$`, {
17
+ escape: false,
18
+ }),
19
+ contentFilter: /function loadManifest\(/,
20
+ callback: async ({ contents }) => {
21
+ contents = await patchCode(contents, await getLoadManifestRule(buildOpts));
22
+ contents = await patchCode(contents, await getEvalManifestRule(buildOpts));
23
+ return contents;
26
24
  },
27
25
  },
28
26
  ]);
@@ -14,21 +14,19 @@ import { normalizePath } from "../../utils/index.js";
14
14
  export function patchNextServer(updater, buildOpts) {
15
15
  return updater.updateContent("next-server", [
16
16
  {
17
- field: {
18
- filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/next-server\.js$`, {
19
- escape: false,
20
- }),
21
- contentFilter: /getBuildId\(/,
22
- callback: async ({ contents }) => {
23
- const { outputDir } = buildOpts;
24
- contents = patchCode(contents, buildIdRule);
25
- const outputPath = path.join(outputDir, "server-functions/default");
26
- const cacheHandler = path.join(outputPath, getPackagePath(buildOpts), "cache.cjs");
27
- contents = patchCode(contents, createCacheHandlerRule(cacheHandler));
28
- const composableCacheHandler = path.join(outputPath, getPackagePath(buildOpts), "composable-cache.cjs");
29
- contents = patchCode(contents, createComposableCacheHandlersRule(composableCacheHandler));
30
- return contents;
31
- },
17
+ filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/next-server\.js$`, {
18
+ escape: false,
19
+ }),
20
+ contentFilter: /getBuildId\(/,
21
+ callback: async ({ contents }) => {
22
+ const { outputDir } = buildOpts;
23
+ contents = patchCode(contents, buildIdRule);
24
+ const outputPath = path.join(outputDir, "server-functions/default");
25
+ const cacheHandler = path.join(outputPath, getPackagePath(buildOpts), "cache.cjs");
26
+ contents = patchCode(contents, createCacheHandlerRule(cacheHandler));
27
+ const composableCacheHandler = path.join(outputPath, getPackagePath(buildOpts), "composable-cache.cjs");
28
+ contents = patchCode(contents, createComposableCacheHandlersRule(composableCacheHandler));
29
+ return contents;
32
30
  },
33
31
  },
34
32
  ]);
@@ -12,14 +12,12 @@ export function patchResolveCache(updater, buildOpts) {
12
12
  const indexPath = path.relative(buildOpts.appBuildOutputPath, path.join(outputPath, packagePath, `index.mjs`));
13
13
  return updater.updateContent("patch-resolve-cache", [
14
14
  {
15
- field: {
16
- filter: getCrossPlatformPathRegex(indexPath),
17
- contentFilter: /cacheHandlerPath/,
18
- callback: async ({ contents }) => {
19
- contents = patchCode(contents, cacheHandlerRule);
20
- contents = patchCode(contents, compositeCacheHandlerRule);
21
- return contents;
22
- },
15
+ filter: getCrossPlatformPathRegex(indexPath),
16
+ contentFilter: /cacheHandlerPath/,
17
+ callback: async ({ contents }) => {
18
+ contents = patchCode(contents, cacheHandlerRule);
19
+ contents = patchCode(contents, compositeCacheHandlerRule);
20
+ return contents;
23
21
  },
24
22
  },
25
23
  ]);
@@ -8,11 +8,9 @@ import { patchCode } from "@opennextjs/aws/build/patch/astCodePatcher.js";
8
8
  export function patchDepdDeprecations(updater) {
9
9
  return updater.updateContent("patch-depd-deprecations", [
10
10
  {
11
- field: {
12
- filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
13
- contentFilter: /argument fn must be a function/,
14
- callback: ({ contents }) => patchCode(contents, rule),
15
- },
11
+ filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
12
+ contentFilter: /argument fn must be a function/,
13
+ callback: ({ contents }) => patchCode(contents, rule),
16
14
  },
17
15
  ]);
18
16
  }
@@ -1,44 +1,42 @@
1
1
  export function fixRequire(updater) {
2
2
  return updater.updateContent("fix-require", [
3
3
  {
4
- field: {
5
- filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
6
- contentFilter: /.*/,
7
- callback: ({ contents }) => {
8
- // `eval(...)` is not supported by workerd.
9
- contents = contents.replaceAll(`eval("require")`, "require");
10
- // `@opentelemetry` has a few issues.
11
- //
12
- // Next.js has the following code in `next/dist/server/lib/trace/tracer.js`:
13
- //
14
- // try {
15
- // api = require('@opentelemetry/api');
16
- // } catch (err) {
17
- // api = require('next/dist/compiled/@opentelemetry/api');
18
- // }
19
- //
20
- // The intent is to allow users to install their own version of `@opentelemetry/api`.
21
- //
22
- // The problem is that even when users do not explicitly install `@opentelemetry/api`,
23
- // `require('@opentelemetry/api')` resolves to the package which is a dependency
24
- // of Next.
25
- //
26
- // The second problem is that when Next traces files, it would not copy the `api/build/esm`
27
- // folder (used by the `module` conditions in package.json) it would only copy `api/build/src`.
28
- // This could be solved by updating the next config:
29
- //
30
- // const nextConfig: NextConfig = {
31
- // // ...
32
- // outputFileTracingIncludes: {
33
- // "*": ["./node_modules/@opentelemetry/api/build/**/*"],
34
- // },
35
- // };
36
- //
37
- // We can consider doing that when we want to enable users to install their own version
38
- // of `@opentelemetry/api`. For now we simply use the pre-compiled version.
39
- contents = contents.replace(/require\(.@opentelemetry\/api.\)/g, `require("next/dist/compiled/@opentelemetry/api")`);
40
- return contents;
41
- },
4
+ filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/,
5
+ contentFilter: /.*/,
6
+ callback: ({ contents }) => {
7
+ // `eval(...)` is not supported by workerd.
8
+ contents = contents.replaceAll(`eval("require")`, "require");
9
+ // `@opentelemetry` has a few issues.
10
+ //
11
+ // Next.js has the following code in `next/dist/server/lib/trace/tracer.js`:
12
+ //
13
+ // try {
14
+ // api = require('@opentelemetry/api');
15
+ // } catch (err) {
16
+ // api = require('next/dist/compiled/@opentelemetry/api');
17
+ // }
18
+ //
19
+ // The intent is to allow users to install their own version of `@opentelemetry/api`.
20
+ //
21
+ // The problem is that even when users do not explicitly install `@opentelemetry/api`,
22
+ // `require('@opentelemetry/api')` resolves to the package which is a dependency
23
+ // of Next.
24
+ //
25
+ // The second problem is that when Next traces files, it would not copy the `api/build/esm`
26
+ // folder (used by the `module` conditions in package.json) it would only copy `api/build/src`.
27
+ // This could be solved by updating the next config:
28
+ //
29
+ // const nextConfig: NextConfig = {
30
+ // // ...
31
+ // outputFileTracingIncludes: {
32
+ // "*": ["./node_modules/@opentelemetry/api/build/**/*"],
33
+ // },
34
+ // };
35
+ //
36
+ // We can consider doing that when we want to enable users to install their own version
37
+ // of `@opentelemetry/api`. For now we simply use the pre-compiled version.
38
+ contents = contents.replace(/require\(.@opentelemetry\/api.\)/g, `require("next/dist/compiled/@opentelemetry/api")`);
39
+ return contents;
42
40
  },
43
41
  },
44
42
  ]);
@@ -65,13 +65,11 @@ export const patchResRevalidate = {
65
65
  patches: [
66
66
  {
67
67
  versions: ">=14.2.0",
68
- field: {
69
- pathFilter: getCrossPlatformPathRegex(String.raw `(pages-api\.runtime\.prod\.js|node/api-resolver\.js)$`, {
70
- escape: false,
71
- }),
72
- contentFilter: /\.trustHostHeader/,
73
- patchCode: async ({ code }) => patchCode(code, rule),
74
- },
68
+ pathFilter: getCrossPlatformPathRegex(String.raw `(pages-api\.runtime\.prod\.js|node/api-resolver\.js)$`, {
69
+ escape: false,
70
+ }),
71
+ contentFilter: /\.trustHostHeader/,
72
+ patchCode: async ({ code }) => patchCode(code, rule),
75
73
  },
76
74
  ],
77
75
  };
@@ -28,13 +28,11 @@ export const patchUseCacheIO = {
28
28
  patches: [
29
29
  {
30
30
  versions: ">=15.3.1",
31
- field: {
32
- pathFilter: getCrossPlatformPathRegex(String.raw `server/app-render/async-local-storage\.js$`, {
33
- escape: false,
34
- }),
35
- contentFilter: /createSnapshot/,
36
- patchCode: async ({ code }) => patchCode(code, rule),
37
- },
31
+ pathFilter: getCrossPlatformPathRegex(String.raw `server/app-render/async-local-storage\.js$`, {
32
+ escape: false,
33
+ }),
34
+ contentFilter: /createSnapshot/,
35
+ patchCode: async ({ code }) => patchCode(code, rule),
38
36
  },
39
37
  ],
40
38
  };
@@ -26,7 +26,7 @@ export declare function matchLocalPattern(pattern: LocalPattern, url: URL): bool
26
26
  * @param buffer The image bytes
27
27
  * @returns a content type of undefined for unsupported content
28
28
  */
29
- export declare function detectContentType(buffer: Uint8Array): "image/svg+xml" | "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/avif" | "image/x-icon" | "image/x-icns" | "image/tiff" | "image/bmp" | undefined;
29
+ export declare function detectContentType(buffer: Uint8Array): "image/svg+xml" | "image/jpeg" | "image/png" | "image/gif" | "image/webp" | "image/avif" | "image/x-icon" | "image/x-icns" | "image/tiff" | "image/bmp" | "image/jxl" | "image/heic" | "application/pdf" | "image/jp2" | undefined;
30
30
  declare global {
31
31
  var __IMAGES_REMOTE_PATTERNS__: RemotePattern[];
32
32
  var __IMAGES_LOCAL_PATTERNS__: LocalPattern[];
@@ -65,12 +65,15 @@ export async function fetchImage(fetcher, imageUrl, ctx) {
65
65
  contentType = detectContentType(value);
66
66
  }
67
67
  if (!contentType) {
68
- // Fallback to the sanitized upstream header when the type can not be detected
68
+ // Fallback to upstream header when the type can not be detected
69
69
  // https://github.com/vercel/next.js/blob/d76f0b1/packages/next/src/server/image-optimizer.ts#L748
70
- const header = imgResponse.headers.get("content-type") ?? "";
71
- if (header.startsWith("image/") && !header.includes(",")) {
72
- contentType = header;
73
- }
70
+ contentType = imgResponse.headers.get("content-type") ?? "";
71
+ }
72
+ // Sanitize the content type:
73
+ // - Accept images only
74
+ // - Reject multiple content types
75
+ if (!contentType.startsWith("image/") || contentType.includes(",")) {
76
+ contentType = undefined;
74
77
  }
75
78
  if (contentType && !(contentType === SVG && !__IMAGES_ALLOW_SVG__)) {
76
79
  const headers = new Headers(imgResponse.headers);
@@ -126,12 +129,17 @@ const AVIF = "image/avif";
126
129
  const WEBP = "image/webp";
127
130
  const PNG = "image/png";
128
131
  const JPEG = "image/jpeg";
132
+ const JXL = "image/jxl";
133
+ const JP2 = "image/jp2";
134
+ const HEIC = "image/heic";
129
135
  const GIF = "image/gif";
130
136
  const SVG = "image/svg+xml";
131
137
  const ICO = "image/x-icon";
132
138
  const ICNS = "image/x-icns";
133
139
  const TIFF = "image/tiff";
134
140
  const BMP = "image/bmp";
141
+ // pdf will be rejected (not an `image/...` type)
142
+ const PDF = "application/pdf";
135
143
  /**
136
144
  * Detects the content type by looking at the first few bytes of a file
137
145
  *
@@ -174,4 +182,19 @@ export function detectContentType(buffer) {
174
182
  if ([0x42, 0x4d].every((b, i) => buffer[i] === b)) {
175
183
  return BMP;
176
184
  }
185
+ if ([0xff, 0x0a].every((b, i) => buffer[i] === b)) {
186
+ return JXL;
187
+ }
188
+ if ([0x00, 0x00, 0x00, 0x0c, 0x4a, 0x58, 0x4c, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every((b, i) => buffer[i] === b)) {
189
+ return JXL;
190
+ }
191
+ if ([0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63].every((b, i) => !b || buffer[i] === b)) {
192
+ return HEIC;
193
+ }
194
+ if ([0x25, 0x50, 0x44, 0x46, 0x2d].every((b, i) => buffer[i] === b)) {
195
+ return PDF;
196
+ }
197
+ if ([0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every((b, i) => buffer[i] === b)) {
198
+ return JP2;
199
+ }
177
200
  }
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.6.2",
4
+ "version": "1.6.3",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "opennextjs-cloudflare": "dist/cli/index.js"
@@ -43,7 +43,7 @@
43
43
  "homepage": "https://github.com/opennextjs/opennextjs-cloudflare",
44
44
  "dependencies": {
45
45
  "@dotenvx/dotenvx": "1.31.0",
46
- "@opennextjs/aws": "3.7.1",
46
+ "@opennextjs/aws": "3.7.2",
47
47
  "cloudflare": "^4.4.1",
48
48
  "enquirer": "^2.4.1",
49
49
  "glob": "^11.0.0",