@solcreek/adapter-creek 0.1.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.
- package/LICENSE +190 -0
- package/README.md +184 -0
- package/dist/build.d.ts +57 -0
- package/dist/build.js +1382 -0
- package/dist/bundler.d.ts +20 -0
- package/dist/bundler.js +991 -0
- package/dist/cache-handler.d.ts +32 -0
- package/dist/cache-handler.js +100 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +247 -0
- package/dist/manifest.d.ts +40 -0
- package/dist/manifest.js +27 -0
- package/dist/worker-entry.d.ts +133 -0
- package/dist/worker-entry.js +7734 -0
- package/package.json +64 -0
- package/src/shims/als-polyfill.js +7 -0
- package/src/shims/critters.js +7 -0
- package/src/shims/empty.js +2 -0
- package/src/shims/env.js +3 -0
- package/src/shims/fast-set-immediate.js +285 -0
- package/src/shims/fs.js +225 -0
- package/src/shims/http.js +240 -0
- package/src/shims/image-optimizer.js +18 -0
- package/src/shims/load-manifest.js +123 -0
- package/src/shims/opentelemetry.js +229 -0
- package/src/shims/sharp.js +12 -0
- package/src/shims/sqlite3-binding.js +517 -0
- package/src/shims/track-module-loading.js +68 -0
- package/src/shims/vm.js +49 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache handler for Next.js ISR on Cloudflare Workers.
|
|
3
|
+
*
|
|
4
|
+
* Implements the cacheHandler interface (get/set/revalidateTag/resetRequestCache).
|
|
5
|
+
* Uses in-memory Map for single-instance caching.
|
|
6
|
+
*
|
|
7
|
+
* TODO: Phase 2 — migrate to Durable Objects for persistent, multi-instance cache
|
|
8
|
+
* with tag-based invalidation via DOShardedTagCache.
|
|
9
|
+
*/
|
|
10
|
+
export default class CacheHandler {
|
|
11
|
+
constructor(_ctx?: unknown);
|
|
12
|
+
get(key: string, _ctx?: {
|
|
13
|
+
kind?: string;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
value: unknown;
|
|
16
|
+
lastModified: number;
|
|
17
|
+
age: number;
|
|
18
|
+
cacheState: "stale";
|
|
19
|
+
} | {
|
|
20
|
+
value: unknown;
|
|
21
|
+
lastModified: number;
|
|
22
|
+
age: number;
|
|
23
|
+
cacheState: "fresh";
|
|
24
|
+
} | null>;
|
|
25
|
+
set(key: string, data: unknown | null, ctx?: {
|
|
26
|
+
tags?: string[];
|
|
27
|
+
revalidate?: number | false;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
revalidateTag(tag: string | string[]): Promise<void>;
|
|
30
|
+
resetRequestCache(): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=cache-handler.d.ts.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache handler for Next.js ISR on Cloudflare Workers.
|
|
3
|
+
*
|
|
4
|
+
* Implements the cacheHandler interface (get/set/revalidateTag/resetRequestCache).
|
|
5
|
+
* Uses in-memory Map for single-instance caching.
|
|
6
|
+
*
|
|
7
|
+
* TODO: Phase 2 — migrate to Durable Objects for persistent, multi-instance cache
|
|
8
|
+
* with tag-based invalidation via DOShardedTagCache.
|
|
9
|
+
*/
|
|
10
|
+
const cache = new Map();
|
|
11
|
+
const tagToKeys = new Map();
|
|
12
|
+
// When a tag is invalidated via revalidateTag(), we record the wall-clock
|
|
13
|
+
// timestamp here. Subsequent get() calls compare this against the entry's
|
|
14
|
+
// lastModified — if the tag was invalidated AFTER the entry was written,
|
|
15
|
+
// the entry is treated as stale (cacheState: "stale") rather than missing.
|
|
16
|
+
//
|
|
17
|
+
// This implements stale-while-revalidate semantics: Next.js receives the
|
|
18
|
+
// old value plus the stale signal and decides to serve it while triggering
|
|
19
|
+
// a background re-render. Aligned with opennextjs-cloudflare#1168.
|
|
20
|
+
const tagInvalidatedAt = new Map();
|
|
21
|
+
function isStaleByTags(entry) {
|
|
22
|
+
for (const tag of entry.tags) {
|
|
23
|
+
const invalidatedAt = tagInvalidatedAt.get(tag);
|
|
24
|
+
if (invalidatedAt !== undefined && invalidatedAt > entry.lastModified) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
export default class CacheHandler {
|
|
31
|
+
constructor(_ctx) {
|
|
32
|
+
// Context includes serverDistDir, dev, etc.
|
|
33
|
+
// Not needed for in-memory implementation.
|
|
34
|
+
}
|
|
35
|
+
async get(key, _ctx) {
|
|
36
|
+
const entry = cache.get(key);
|
|
37
|
+
if (!entry)
|
|
38
|
+
return null;
|
|
39
|
+
const age = (Date.now() - entry.lastModified) / 1000;
|
|
40
|
+
// Stale if either (a) any of its tags was invalidated since write, or
|
|
41
|
+
// (b) time-based revalidate has elapsed.
|
|
42
|
+
const staleByTag = isStaleByTags(entry);
|
|
43
|
+
const staleByTime = entry.revalidate !== undefined &&
|
|
44
|
+
entry.revalidate !== false &&
|
|
45
|
+
(entry.revalidate === 0 || age > entry.revalidate);
|
|
46
|
+
if (staleByTag || staleByTime) {
|
|
47
|
+
return {
|
|
48
|
+
value: entry.value,
|
|
49
|
+
lastModified: entry.lastModified,
|
|
50
|
+
age: Math.floor(age),
|
|
51
|
+
cacheState: "stale",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
value: entry.value,
|
|
56
|
+
lastModified: entry.lastModified,
|
|
57
|
+
age: Math.floor(age),
|
|
58
|
+
cacheState: "fresh",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async set(key, data, ctx) {
|
|
62
|
+
if (data === null) {
|
|
63
|
+
cache.delete(key);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const tags = ctx?.tags ?? [];
|
|
67
|
+
const revalidate = typeof ctx?.revalidate === "number" ? ctx.revalidate : undefined;
|
|
68
|
+
cache.set(key, {
|
|
69
|
+
value: data,
|
|
70
|
+
lastModified: Date.now(),
|
|
71
|
+
tags,
|
|
72
|
+
revalidate,
|
|
73
|
+
});
|
|
74
|
+
// Index by tags for revalidateTag()
|
|
75
|
+
for (const tag of tags) {
|
|
76
|
+
let keys = tagToKeys.get(tag);
|
|
77
|
+
if (!keys) {
|
|
78
|
+
keys = new Set();
|
|
79
|
+
tagToKeys.set(tag, keys);
|
|
80
|
+
}
|
|
81
|
+
keys.add(key);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async revalidateTag(tag) {
|
|
85
|
+
const tags = Array.isArray(tag) ? tag : [tag];
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
// Mark each tag as invalidated NOW. Existing entries become stale on
|
|
88
|
+
// the next get(); fresh writes (lastModified > now) are unaffected.
|
|
89
|
+
// We do NOT delete entries — Next.js wants to serve them as stale
|
|
90
|
+
// while it re-renders in the background.
|
|
91
|
+
for (const t of tags) {
|
|
92
|
+
tagInvalidatedAt.set(t, now);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
resetRequestCache() {
|
|
96
|
+
// No per-request cache to reset in this implementation.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
;
|
|
100
|
+
//# sourceMappingURL=cache-handler.js.map
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
4
|
+
import { handleBuild } from "./build.js";
|
|
5
|
+
/**
|
|
6
|
+
* Detect the monorepo root by walking up looking for workspace markers.
|
|
7
|
+
*/
|
|
8
|
+
function findRepoRoot(startDir) {
|
|
9
|
+
let dir = startDir;
|
|
10
|
+
while (true) {
|
|
11
|
+
if (existsSync(path.join(dir, "pnpm-workspace.yaml")) ||
|
|
12
|
+
existsSync(path.join(dir, "turbo.json"))) {
|
|
13
|
+
return dir;
|
|
14
|
+
}
|
|
15
|
+
const pkgPath = path.join(dir, "package.json");
|
|
16
|
+
if (existsSync(pkgPath)) {
|
|
17
|
+
try {
|
|
18
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
19
|
+
if (pkg.workspaces)
|
|
20
|
+
return dir;
|
|
21
|
+
}
|
|
22
|
+
catch { }
|
|
23
|
+
}
|
|
24
|
+
const parent = path.dirname(dir);
|
|
25
|
+
if (parent === dir)
|
|
26
|
+
break;
|
|
27
|
+
dir = parent;
|
|
28
|
+
}
|
|
29
|
+
return startDir;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Detect direct dependencies whose `.js` entry files contain JSX.
|
|
33
|
+
*
|
|
34
|
+
* Turbopack at the pinned Next.js canary has a regression where it fails
|
|
35
|
+
* to parse JSX inside `.js` files shipped by a workspace-linked / third-
|
|
36
|
+
* party package (exit message: `Expected ';', got 'ident'`). The
|
|
37
|
+
* documented fix is to add the package to `transpilePackages` so Next.js
|
|
38
|
+
* runs SWC over it. Vanilla `next build` fails identically on these
|
|
39
|
+
* fixtures without our adapter — but user apps don't get to edit their
|
|
40
|
+
* own `next.config.js` just because we say so, so we auto-inject.
|
|
41
|
+
*
|
|
42
|
+
* Scope: only DIRECT deps. Transitive deps are either already transpiled
|
|
43
|
+
* by their publisher (the common case) or reachable through the direct
|
|
44
|
+
* dep we pick up. Walking all of node_modules would be slow and catch
|
|
45
|
+
* unrelated packages.
|
|
46
|
+
*
|
|
47
|
+
* Detection: we resolve each dep's entry file (`package.json#exports["."]`
|
|
48
|
+
* or `main`) and heuristically look for JSX with strong React hints.
|
|
49
|
+
* False positives cost a little build time (Next.js transpiles an
|
|
50
|
+
* already-ES-code package); false negatives are the status quo. The
|
|
51
|
+
* heuristic is conservative — we require BOTH a JSX construct AND a
|
|
52
|
+
* React signal ('use client' / react import / createElement) to claim
|
|
53
|
+
* a package needs transpile.
|
|
54
|
+
*/
|
|
55
|
+
function detectPackagesNeedingTranspile(projectDir) {
|
|
56
|
+
let projectPkg;
|
|
57
|
+
try {
|
|
58
|
+
projectPkg = JSON.parse(readFileSync(path.join(projectDir, "package.json"), "utf-8"));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
const directDeps = new Set();
|
|
64
|
+
for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
|
|
65
|
+
const map = projectPkg[field];
|
|
66
|
+
if (map && typeof map === "object") {
|
|
67
|
+
for (const name of Object.keys(map))
|
|
68
|
+
directDeps.add(name);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (directDeps.size === 0)
|
|
72
|
+
return [];
|
|
73
|
+
// Don't ever try to transpile Next.js itself or the React runtimes —
|
|
74
|
+
// they're pre-bundled and transpilePackages on them would be an
|
|
75
|
+
// expensive no-op at best, a breakage at worst.
|
|
76
|
+
const SKIP = new Set([
|
|
77
|
+
"next", "react", "react-dom", "react-server-dom-webpack",
|
|
78
|
+
"react-dom/server", "scheduler", "@next/routing", "@next/swc",
|
|
79
|
+
"@solcreek/adapter-creek",
|
|
80
|
+
]);
|
|
81
|
+
const needsTranspile = [];
|
|
82
|
+
for (const dep of directDeps) {
|
|
83
|
+
if (SKIP.has(dep))
|
|
84
|
+
continue;
|
|
85
|
+
// Ignore subpath-qualified entries that aren't real packages (shouldn't
|
|
86
|
+
// show up in dependencies, but be defensive).
|
|
87
|
+
if (dep.includes("/") && !dep.startsWith("@"))
|
|
88
|
+
continue;
|
|
89
|
+
// Locate the package root via direct node_modules path. Can't use
|
|
90
|
+
// `require.resolve(dep + '/package.json')` — Node's resolver honors
|
|
91
|
+
// the `exports` field and most packages don't expose `./package.json`.
|
|
92
|
+
// pnpm's flat node_modules layout hoists a symlink at
|
|
93
|
+
// `node_modules/<dep>` for every direct + hoisted dep, so this works
|
|
94
|
+
// across npm, yarn, pnpm.
|
|
95
|
+
const pkgRoot = path.join(projectDir, "node_modules", dep);
|
|
96
|
+
const pkgJsonPath = path.join(pkgRoot, "package.json");
|
|
97
|
+
let pkgJson;
|
|
98
|
+
try {
|
|
99
|
+
pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Skip packages that declare themselves ES (module field points at
|
|
105
|
+
// .mjs) AND ship no .js siblings — transpile wouldn't kick in for
|
|
106
|
+
// them anyway. We still process packages whose `main` is a .js.
|
|
107
|
+
const entryCandidates = collectEntryFiles(pkgJson, pkgRoot);
|
|
108
|
+
if (entryCandidates.length === 0)
|
|
109
|
+
continue;
|
|
110
|
+
for (const entry of entryCandidates) {
|
|
111
|
+
try {
|
|
112
|
+
const content = readFileSync(entry, "utf-8");
|
|
113
|
+
if (looksLikeJsxInJs(content, entry)) {
|
|
114
|
+
needsTranspile.push(dep);
|
|
115
|
+
break; // one hit is enough; move to next package
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch { }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return needsTranspile;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Pick the `.js` entry file(s) for a package. Only files that end in `.js`
|
|
125
|
+
* (and not `.mjs` / `.cjs`) are eligible — the others are either module-
|
|
126
|
+
* specific formats (where Turbopack's JSX-in-JS bug doesn't apply) or
|
|
127
|
+
* already indicate transpilation happened upstream.
|
|
128
|
+
*/
|
|
129
|
+
function collectEntryFiles(pkgJson, pkgRoot) {
|
|
130
|
+
const candidates = [];
|
|
131
|
+
const tryAdd = (rel) => {
|
|
132
|
+
if (typeof rel !== "string")
|
|
133
|
+
return;
|
|
134
|
+
if (!rel.endsWith(".js"))
|
|
135
|
+
return;
|
|
136
|
+
const abs = path.join(pkgRoot, rel.startsWith("./") ? rel.slice(2) : rel);
|
|
137
|
+
try {
|
|
138
|
+
if (statSync(abs).isFile())
|
|
139
|
+
candidates.push(abs);
|
|
140
|
+
}
|
|
141
|
+
catch { }
|
|
142
|
+
};
|
|
143
|
+
tryAdd(pkgJson.main);
|
|
144
|
+
// `exports` can be a string, or a nested conditional object. We walk
|
|
145
|
+
// the "." entry's import/require/default branches.
|
|
146
|
+
const exports_ = pkgJson.exports;
|
|
147
|
+
if (typeof exports_ === "string") {
|
|
148
|
+
tryAdd(exports_);
|
|
149
|
+
}
|
|
150
|
+
else if (exports_ && typeof exports_ === "object") {
|
|
151
|
+
const rootExport = exports_["."] ?? exports_;
|
|
152
|
+
if (typeof rootExport === "string") {
|
|
153
|
+
tryAdd(rootExport);
|
|
154
|
+
}
|
|
155
|
+
else if (rootExport && typeof rootExport === "object") {
|
|
156
|
+
for (const cond of ["default", "import", "require", "node", "browser"]) {
|
|
157
|
+
tryAdd(rootExport[cond]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return [...new Set(candidates)];
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Heuristic: a `.js` file looks like it contains JSX if it has at least
|
|
165
|
+
* one JSX-ish token AND at least one React signal. Both conditions keeps
|
|
166
|
+
* false positives low (e.g. plain TS generics `function f<T>()` without
|
|
167
|
+
* React imports won't trigger).
|
|
168
|
+
*/
|
|
169
|
+
function looksLikeJsxInJs(content, filePath) {
|
|
170
|
+
if (!filePath.endsWith(".js"))
|
|
171
|
+
return false;
|
|
172
|
+
const head = content.slice(0, 20_000); // cap scan cost
|
|
173
|
+
const JSX_HINTS = [
|
|
174
|
+
/return\s*\(\s*</, // return (<...
|
|
175
|
+
/return\s+<[A-Za-z]/, // return <Tag or <Component
|
|
176
|
+
/=>\s*<[A-Za-z]/, // arrow => <...
|
|
177
|
+
/\bcreateElement\s*\(/, // raw createElement
|
|
178
|
+
];
|
|
179
|
+
const hasJsxHint = JSX_HINTS.some((re) => re.test(head));
|
|
180
|
+
if (!hasJsxHint)
|
|
181
|
+
return false;
|
|
182
|
+
const REACT_HINTS = [
|
|
183
|
+
/['"]use client['"]/,
|
|
184
|
+
/from\s+['"]react['"]/,
|
|
185
|
+
/require\s*\(\s*['"]react['"]\s*\)/,
|
|
186
|
+
/\bReact\.createElement\b/,
|
|
187
|
+
];
|
|
188
|
+
return REACT_HINTS.some((re) => re.test(head));
|
|
189
|
+
}
|
|
190
|
+
const cacheHandlerPath = fileURLToPath(new URL("./cache-handler.js", import.meta.url));
|
|
191
|
+
const adapter = {
|
|
192
|
+
name: "adapter-creek",
|
|
193
|
+
modifyConfig(config, { phase }) {
|
|
194
|
+
if (phase !== "phase-production-build")
|
|
195
|
+
return config;
|
|
196
|
+
const projectDir = process.cwd();
|
|
197
|
+
const repoRoot = findRepoRoot(projectDir);
|
|
198
|
+
const isMonorepo = repoRoot !== projectDir;
|
|
199
|
+
const installedCacheHandlerPath = path.join(projectDir, "node_modules", "@solcreek", "adapter-creek", "dist", "cache-handler.js");
|
|
200
|
+
const resolvedCacheHandlerPath = existsSync(installedCacheHandlerPath)
|
|
201
|
+
? installedCacheHandlerPath
|
|
202
|
+
: cacheHandlerPath;
|
|
203
|
+
// Auto-add any direct dep that ships JSX in `.js` to transpilePackages.
|
|
204
|
+
// Works around a Turbopack regression where JSX inside `.js` files from
|
|
205
|
+
// a workspace-linked / third-party package fails to parse with
|
|
206
|
+
// `Expected ';', got 'ident'`. The documented upstream fix is exactly
|
|
207
|
+
// `transpilePackages: [pkg]`; doing this here means user apps don't
|
|
208
|
+
// have to know about it.
|
|
209
|
+
const detected = detectPackagesNeedingTranspile(projectDir);
|
|
210
|
+
const existing = Array.isArray(config.transpilePackages) ? config.transpilePackages : [];
|
|
211
|
+
const transpilePackages = detected.length > 0
|
|
212
|
+
? [...new Set([...existing, ...detected])]
|
|
213
|
+
: existing;
|
|
214
|
+
if (detected.length > 0) {
|
|
215
|
+
console.log(` [Creek Adapter] auto-transpile: ${JSON.stringify(detected)} (JSX in .js entry)`);
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
...config,
|
|
219
|
+
// Disable memory cache — CF Workers doesn't have persistent fs.
|
|
220
|
+
// The runtime cache handler is inlined in the worker entry (CreekCacheHandler).
|
|
221
|
+
cacheMaxMemorySize: 0,
|
|
222
|
+
// Cap maxPostponedStateSize so Next.js's zlib inflate (5x this) stays
|
|
223
|
+
// under workerd's 128MB max output length. Default is 100MB → 500MB
|
|
224
|
+
// decompressed → workerd RangeError. 20MB compressed → 100MB decompressed
|
|
225
|
+
// → safely under limit. Real PPR fallback shells are typically ≤ a few
|
|
226
|
+
// KB anyway, so this cap is purely defensive.
|
|
227
|
+
experimental: {
|
|
228
|
+
...(config.experimental ?? {}),
|
|
229
|
+
maxPostponedStateSize: "20mb",
|
|
230
|
+
},
|
|
231
|
+
// Skip TypeScript type checking during build — CF Workers adapter
|
|
232
|
+
// builds run `next build` where TS errors block the build. Type
|
|
233
|
+
// checking should happen before deployment, not during bundling.
|
|
234
|
+
typescript: { ...config.typescript, ignoreBuildErrors: true },
|
|
235
|
+
...(transpilePackages.length > 0 && { transpilePackages }),
|
|
236
|
+
// Monorepo: set tracing root so Next.js traces deps from repo root
|
|
237
|
+
...(isMonorepo && {
|
|
238
|
+
outputFileTracingRoot: repoRoot,
|
|
239
|
+
}),
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
async onBuildComplete(ctx) {
|
|
243
|
+
await handleBuild(ctx);
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
export default adapter;
|
|
247
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy manifest for Creek CLI.
|
|
3
|
+
*
|
|
4
|
+
* Written to .creek/adapter-output/manifest.json after build.
|
|
5
|
+
* Creek CLI reads this to know how to upload and deploy.
|
|
6
|
+
*/
|
|
7
|
+
export interface DeployManifest {
|
|
8
|
+
/** Manifest schema version */
|
|
9
|
+
version: 1;
|
|
10
|
+
/** Next.js build ID */
|
|
11
|
+
buildId: string;
|
|
12
|
+
/** Next.js version used */
|
|
13
|
+
nextVersion: string;
|
|
14
|
+
/** Framework identifier */
|
|
15
|
+
framework: "nextjs";
|
|
16
|
+
/** Main worker entry file name (relative to server/) */
|
|
17
|
+
entrypoint: string;
|
|
18
|
+
/** All files in server/ directory */
|
|
19
|
+
serverFiles: string[];
|
|
20
|
+
/** Asset directory name (relative to adapter-output/) */
|
|
21
|
+
assetDir: "assets";
|
|
22
|
+
/** CF Workers compatibility settings */
|
|
23
|
+
compatibilityDate: string;
|
|
24
|
+
compatibilityFlags: string[];
|
|
25
|
+
/** Whether middleware is present */
|
|
26
|
+
hasMiddleware: boolean;
|
|
27
|
+
/** Whether prerenders exist (signals ISR support needed) */
|
|
28
|
+
hasPrerender: boolean;
|
|
29
|
+
/** Signals control-plane to inject DO bindings for ISR cache */
|
|
30
|
+
doBindings: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare function writeManifest(outputDir: string, opts: {
|
|
33
|
+
buildId: string;
|
|
34
|
+
nextVersion: string;
|
|
35
|
+
entrypoint: string;
|
|
36
|
+
serverFiles: string[];
|
|
37
|
+
hasMiddleware: boolean;
|
|
38
|
+
hasPrerender: boolean;
|
|
39
|
+
}): Promise<void>;
|
|
40
|
+
//# sourceMappingURL=manifest.d.ts.map
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy manifest for Creek CLI.
|
|
3
|
+
*
|
|
4
|
+
* Written to .creek/adapter-output/manifest.json after build.
|
|
5
|
+
* Creek CLI reads this to know how to upload and deploy.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
export async function writeManifest(outputDir, opts) {
|
|
10
|
+
const manifest = {
|
|
11
|
+
version: 1,
|
|
12
|
+
buildId: opts.buildId,
|
|
13
|
+
nextVersion: opts.nextVersion,
|
|
14
|
+
framework: "nextjs",
|
|
15
|
+
entrypoint: opts.entrypoint,
|
|
16
|
+
serverFiles: opts.serverFiles,
|
|
17
|
+
assetDir: "assets",
|
|
18
|
+
compatibilityDate: "2026-03-28",
|
|
19
|
+
compatibilityFlags: ["nodejs_compat_v2"],
|
|
20
|
+
hasMiddleware: opts.hasMiddleware,
|
|
21
|
+
hasPrerender: opts.hasPrerender,
|
|
22
|
+
// Always inject DO bindings for Next.js SSR (ISR cache support)
|
|
23
|
+
doBindings: true,
|
|
24
|
+
};
|
|
25
|
+
await fs.writeFile(path.join(outputDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker entry source code generator.
|
|
3
|
+
*
|
|
4
|
+
* Generates a CF Workers entry that statically imports all Next.js
|
|
5
|
+
* page/route handlers. With --webpack, .next/server/app/*.js are
|
|
6
|
+
* standard CJS modules that esbuild can bundle.
|
|
7
|
+
*/
|
|
8
|
+
import type { NextAdapter } from "next";
|
|
9
|
+
type BuildContext = Parameters<NonNullable<NextAdapter["onBuildComplete"]>>[0];
|
|
10
|
+
export interface WorkerEntryOptions {
|
|
11
|
+
buildId: string;
|
|
12
|
+
routing: BuildContext["routing"];
|
|
13
|
+
outputs: BuildContext["outputs"];
|
|
14
|
+
basePath: string;
|
|
15
|
+
assetPrefix: string;
|
|
16
|
+
i18n: unknown;
|
|
17
|
+
/**
|
|
18
|
+
* Subset of \`next.config\` that the worker runtime needs — \`ROUTING\`
|
|
19
|
+
* doesn't expose these fields directly (trailingSlash is implemented
|
|
20
|
+
* as regex rules in \`beforeMiddleware\`). Carry them separately so
|
|
21
|
+
* code that needs the boolean flag can consult it without reverse-
|
|
22
|
+
* engineering the routing table.
|
|
23
|
+
*/
|
|
24
|
+
config: {
|
|
25
|
+
trailingSlash?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** Embedded manifests: absolute path → file content */
|
|
28
|
+
manifests: Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* User-side text files (data.json, fixtures, i18n messages, etc.) keyed by
|
|
31
|
+
* path relative to outputFileTracingRoot. Read by the fs shim at runtime when
|
|
32
|
+
* route handlers call fs.readFileSync. See build.ts:collectUserFiles().
|
|
33
|
+
*/
|
|
34
|
+
userFiles: Record<string, string>;
|
|
35
|
+
/** Path to Turbopack runtime file (for static import to trigger chunk bundling) */
|
|
36
|
+
turbopackRuntimePath?: string;
|
|
37
|
+
/** Prerender entries for ISR cache seeding */
|
|
38
|
+
prerenderEntries: Array<{
|
|
39
|
+
pathname: string;
|
|
40
|
+
html: string;
|
|
41
|
+
postponedState?: string;
|
|
42
|
+
allowsFallbackShellResume?: boolean;
|
|
43
|
+
initialRevalidate?: number | false;
|
|
44
|
+
initialStatus?: number;
|
|
45
|
+
initialHeaders?: Record<string, string | string[]>;
|
|
46
|
+
pprHeaders?: Record<string, string>;
|
|
47
|
+
lastModified?: number;
|
|
48
|
+
segmentPaths?: string[];
|
|
49
|
+
metaHeaders?: Record<string, string | string[]>;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Composable cache (`'use cache'`) entries extracted from build-time
|
|
53
|
+
* prerenders, keyed by bracket-form shell pathname. Applied request-scoped
|
|
54
|
+
* at runtime so only requests matching a shell see its seeds.
|
|
55
|
+
*/
|
|
56
|
+
composableCacheSeedsByShell?: Array<[
|
|
57
|
+
string,
|
|
58
|
+
Array<{
|
|
59
|
+
key: string;
|
|
60
|
+
value: string;
|
|
61
|
+
tags: string[];
|
|
62
|
+
stale: number;
|
|
63
|
+
timestamp: number;
|
|
64
|
+
expire: number;
|
|
65
|
+
revalidate: number;
|
|
66
|
+
}>
|
|
67
|
+
]>;
|
|
68
|
+
/** Path to edge registration chunk (contains _ENTRIES setup) */
|
|
69
|
+
edgeRegistrationChunkPath?: string;
|
|
70
|
+
/** Turbopack runtime module IDs for edge middleware evaluation */
|
|
71
|
+
edgeRuntimeModuleIds?: number[];
|
|
72
|
+
/** Paths to edge otherChunks that need explicit import */
|
|
73
|
+
edgeOtherChunkPaths?: string[];
|
|
74
|
+
/**
|
|
75
|
+
* Path to `.next/server/edge-runtime-webpack.js` when the user built with
|
|
76
|
+
* `next build --webpack`. This tiny IIFE installs the chunk-push hook on
|
|
77
|
+
* `self.webpackChunk_N_E`; it must evaluate BEFORE `middleware.js` so the
|
|
78
|
+
* push that registers chunk 149 triggers entry evaluation and populates
|
|
79
|
+
* `_ENTRIES["middleware_middleware"]`. Turbopack builds don't emit this
|
|
80
|
+
* file — its absence is the signal to fall through to the Turbopack path.
|
|
81
|
+
*/
|
|
82
|
+
webpackEdgeRuntimePath?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Path to a tiny generated bootstrap file that predeclares
|
|
85
|
+
* `globalThis._ENTRIES`. Imported BEFORE the webpack runtime so that
|
|
86
|
+
* middleware.js's strict-mode bare `_ENTRIES = {}` has a global to resolve
|
|
87
|
+
* against (otherwise: ReferenceError at module evaluation).
|
|
88
|
+
*/
|
|
89
|
+
webpackEdgeBootstrapPath?: string;
|
|
90
|
+
/**
|
|
91
|
+
* [xxh3_128_hex, wasm_filename_with_ext] pairs. Turbopack edge bundles
|
|
92
|
+
* access the compiled WebAssembly.Module via \`globalThis.wasm_<hex>\`.
|
|
93
|
+
* Import each wasm (wrangler declares \`.wasm\` as CompiledWasm) and
|
|
94
|
+
* assign onto globalThis before edge modules evaluate.
|
|
95
|
+
*/
|
|
96
|
+
wasmHashToFilename?: Array<[string, string]>;
|
|
97
|
+
/**
|
|
98
|
+
* [byteLength, wasm_filename] pairs. Registered in
|
|
99
|
+
* \`globalThis.__CREEK_WASM_BY_LENGTH\` so the runtime
|
|
100
|
+
* \`WebAssembly.instantiate\` patch can swap byte-based calls for the
|
|
101
|
+
* pre-compiled Module workerd already has in memory.
|
|
102
|
+
*/
|
|
103
|
+
wasmLengthToFilename?: Array<[number, string]>;
|
|
104
|
+
/**
|
|
105
|
+
* Module specifiers that Turbopack marked as externals but that the
|
|
106
|
+
* user's code references at runtime via dynamic import. \`id\` is the
|
|
107
|
+
* exact runtime specifier passed to Turbopack's externalImport helper;
|
|
108
|
+
* \`importSpecifier\` is the concrete module path we ask wrangler to
|
|
109
|
+
* bundle for that id.
|
|
110
|
+
*/
|
|
111
|
+
externalModules?: Array<{
|
|
112
|
+
id: string;
|
|
113
|
+
importSpecifier: string;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Absolute path to the user's \`.next/server/instrumentation.js\` when the
|
|
117
|
+
* project actually provides one (not our \`module.exports = {}\` placeholder).
|
|
118
|
+
* We static-import it from the worker entry so wrangler bundles the full
|
|
119
|
+
* module graph, then hand it to Next.js's \`getInstrumentationModule\`
|
|
120
|
+
* lookup — otherwise the dynamic \`__require\` falls back to undefined on
|
|
121
|
+
* workerd and \`instrumentation.register()\` is never called.
|
|
122
|
+
* Fixes e2e/opentelemetry/client-trace-metadata (5 tests) and any other
|
|
123
|
+
* test that depends on user instrumentation side effects.
|
|
124
|
+
*/
|
|
125
|
+
userInstrumentationPath?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Generate the worker entry source code.
|
|
129
|
+
* All handler modules are statically imported so esbuild bundles them.
|
|
130
|
+
*/
|
|
131
|
+
export declare function generateWorkerEntry(opts: WorkerEntryOptions): string;
|
|
132
|
+
export {};
|
|
133
|
+
//# sourceMappingURL=worker-entry.d.ts.map
|