@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.
@@ -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
@@ -0,0 +1,4 @@
1
+ import type { NextAdapter } from "next";
2
+ declare const adapter: NextAdapter;
3
+ export default adapter;
4
+ //# sourceMappingURL=index.d.ts.map
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
@@ -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