Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/forty-cars-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@opennextjs/aws": minor
---

Added some override for debugging OpenNext locally
2 changes: 2 additions & 0 deletions packages/open-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@
"aws4fetch": "^1.0.18",
"chalk": "^5.3.0",
"esbuild": "0.19.2",
"express": "5.0.1",
"path-to-regexp": "^6.3.0",
"promise.series": "^0.2.0",
"urlpattern-polyfill": "^10.0.0"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.109",
"@types/express": "5.0.0",
"@types/node": "catalog:",
"tsc-alias": "^1.8.8",
"typescript": "catalog:"
Expand Down
3 changes: 2 additions & 1 deletion packages/open-next/src/build/validateConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const compatibilityMatrix: Record<IncludedWrapper, IncludedConverter[]> = {
"cloudflare-edge": ["edge"],
"cloudflare-node": ["edge"],
node: ["node"],
dummy: [],
"express-dev": ["node"],
dummy: ["dummy"],
};

function validateFunctionOptions(fnOptions: FunctionOptions) {
Expand Down
16 changes: 16 additions & 0 deletions packages/open-next/src/overrides/imageLoader/fs-dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import fs from "node:fs";
import type { ImageLoader } from "types/overrides";

export default {
name: "fs-dev",
load: async (url: string) => {
const basePath = "../../assets";
const body = fs.createReadStream(`${basePath}/${url}`);
const contentType = url.endsWith(".png") ? "image/png" : "image/jpeg";
return {
body,
contentType,
cacheControl: "public, max-age=31536000, immutable",
};
},
} satisfies ImageLoader;
36 changes: 36 additions & 0 deletions packages/open-next/src/overrides/incrementalCache/fs-dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { IncrementalCache } from "types/overrides.js";

import fs from "node:fs/promises";
import path from "node:path";

const buildId = process.env.NEXT_BUILD_ID;
const basePath = path.resolve(process.cwd(), `../../cache/${buildId}`);

const getCacheKey = (key: string) => {
return path.join(basePath, `${key}.cache`);
};

const cache: IncrementalCache = {
name: "fs-dev",
get: async (key: string) => {
const fileData = await fs.readFile(getCacheKey(key), "utf-8");
const data = JSON.parse(fileData);
const { mtime } = await fs.stat(getCacheKey(key));
return {
value: data,
lastModified: mtime.getTime(),
};
},
set: async (key, value, isFetch) => {
const data = JSON.stringify(value);
const cacheKey = getCacheKey(key);
// We need to create the directory before writing the file
await fs.mkdir(path.dirname(cacheKey), { recursive: true });
await fs.writeFile(cacheKey, data);
},
delete: async (key) => {
await fs.rm(getCacheKey(key));
},
};

export default cache;
21 changes: 21 additions & 0 deletions packages/open-next/src/overrides/queue/direct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Queue } from "types/overrides.js";

const queue: Queue = {
name: "dev-queue",
send: async (message) => {
const prerenderManifest = (await import("../../adapters/config/index.js"))
.PrerenderManifest as any;
const { host, url } = message.MessageBody;
const protocol = host.includes("localhost") ? "http" : "https";
const revalidateId: string = prerenderManifest.preview.previewModeId;
await globalThis.internalFetch(`${protocol}://${host}${url}`, {
method: "HEAD",
headers: {
"x-prerender-revalidate": revalidateId,
"x-isr": "1",
},
});
},
};

export default queue;
54 changes: 54 additions & 0 deletions packages/open-next/src/overrides/tagCache/fs-dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { TagCache } from "types/overrides";

import fs from "node:fs";

const tagFile = "../../dynamodb-provider/dynamodb-cache.json";

const tagContent = fs.readFileSync(tagFile, "utf-8");

let tags = JSON.parse(tagContent) as {
tag: { S: string };
path: { S: string };
revalidatedAt: { N: string };
}[];

const tagCache: TagCache = {
name: "fs-dev",
getByPath: async (path: string) => {
return tags
.filter((tagPathMapping) => tagPathMapping.path.S === path)
.map((tag) => tag.tag.S);
},
getByTag: async (tag: string) => {
return tags
.filter((tagPathMapping) => tagPathMapping.tag.S === tag)
.map((tag) => tag.path.S);
},
getLastModified: async (path: string, lastModified?: number) => {
const revalidatedTags = tags.filter(
(tagPathMapping) =>
tagPathMapping.path.S === path &&
Number.parseInt(tagPathMapping.revalidatedAt.N) > (lastModified ?? 0),
);
return revalidatedTags.length > 0 ? -1 : (lastModified ?? Date.now());
},
writeTags: async (newTags) => {
const unchangedTags = tags.filter(
(tagPathMapping) =>
!newTags.some(
(tag) =>
tag.tag === tagPathMapping.tag.S &&
tag.path === tagPathMapping.path.S,
),
);
tags = unchangedTags.concat(
newTags.map((tag) => ({
tag: { S: tag.tag },
path: { S: tag.path },
revalidatedAt: { N: String(tag.revalidatedAt) },
})),
);
},
};

export default tagCache;
9 changes: 7 additions & 2 deletions packages/open-next/src/overrides/wrappers/dummy.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import type { InternalEvent, StreamCreator } from "types/open-next";
import type { Wrapper, WrapperHandler } from "types/overrides";

const dummyWrapper: WrapperHandler = async () => async () => undefined;
const dummyWrapper: WrapperHandler = async (handler, converter) => {
return async (event: InternalEvent, responseStream?: StreamCreator) => {
return await handler(event, responseStream);
};
};

export default {
name: "dummy",
wrapper: dummyWrapper,
supportStreaming: false,
supportStreaming: true,
} satisfies Wrapper;
57 changes: 57 additions & 0 deletions packages/open-next/src/overrides/wrappers/express-dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import express from "express";

import type { StreamCreator } from "types/open-next.js";
import type { WrapperHandler } from "types/overrides.js";

const wrapper: WrapperHandler = async (handler, converter) => {
const app = express();
// To serve static assets
app.use(express.static("../../assets"));

const imageHandlerPath = "../../image-optimization-function/index.mjs";
const imageHandler = await import(imageHandlerPath).then((m) => m.handler);

app.all("/_next/image", async (req, res) => {
const internalEvent = await converter.convertFrom(req);
const _res: StreamCreator = {
writeHeaders: (prelude) => {
res.writeHead(prelude.statusCode, prelude.headers);
return res;
},
};
await imageHandler(internalEvent, _res);
});

app.all("*paths", async (req, res) => {
const internalEvent = await converter.convertFrom(req);
const _res: StreamCreator = {
writeHeaders: (prelude) => {
res.writeHead(prelude.statusCode, prelude.headers);
return res;
},
onFinish: () => {},
};
await handler(internalEvent, _res);
});

const server = app.listen(
Number.parseInt(process.env.PORT ?? "3000", 10),
() => {
console.log(`Server running on port ${process.env.PORT ?? 3000}`);
},
);

app.on("error", (err) => {
console.error("error", err);
});

return () => {
server.close();
};
};

export default {
wrapper,
name: "expresss-dev",
supportStreaming: true,
};
13 changes: 9 additions & 4 deletions packages/open-next/src/types/open-next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export type IncludedWrapper =
| "cloudflare"
| "cloudflare-edge"
| "cloudflare-node"
| "express-dev"
| "dummy";

export type IncludedConverter =
Expand Down Expand Up @@ -133,13 +134,17 @@ export interface MiddlewareResult
extends RoutingResult,
BaseEventOrResult<"middleware"> {}

export type IncludedQueue = "sqs" | "sqs-lite" | "dummy";
export type IncludedQueue = "sqs" | "sqs-lite" | "direct" | "dummy";

export type IncludedIncrementalCache = "s3" | "s3-lite" | "dummy";
export type IncludedIncrementalCache = "s3" | "s3-lite" | "fs-dev" | "dummy";

export type IncludedTagCache = "dynamodb" | "dynamodb-lite" | "dummy";
export type IncludedTagCache =
| "dynamodb"
| "dynamodb-lite"
| "fs-dev"
| "dummy";

export type IncludedImageLoader = "s3" | "host" | "dummy";
export type IncludedImageLoader = "s3" | "host" | "fs-dev" | "dummy";

export type IncludedOriginResolver = "pattern-env" | "dummy";

Expand Down
Loading
Loading