@solcreek/adapter-creek 0.1.1 → 0.1.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.
- package/README.md +8 -2
- package/dist/bundler.js +41 -734
- package/dist/cache-handler.d.ts +1 -31
- package/dist/cache-handler.js +8 -98
- package/dist/index.js +25 -222
- package/dist/worker-entry.js +10 -1
- package/package.json +3 -2
- package/src/shims/net.js +44 -0
package/dist/cache-handler.d.ts
CHANGED
|
@@ -1,32 +1,2 @@
|
|
|
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
|
-
}
|
|
1
|
+
export { default } from "@solcreek/adapter-core/cache-handler";
|
|
32
2
|
//# sourceMappingURL=cache-handler.d.ts.map
|
package/dist/cache-handler.js
CHANGED
|
@@ -1,100 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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.
|
|
1
|
+
// Re-export the shared in-memory Next.js ISR cache handler from
|
|
2
|
+
// @solcreek/adapter-core. The implementation now lives there so both
|
|
3
|
+
// adapter-creek and adapter-creekd can share a single tested copy.
|
|
16
4
|
//
|
|
17
|
-
// This
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
;
|
|
5
|
+
// This file exists for backwards compatibility: users who set
|
|
6
|
+
// `cacheHandler: require.resolve("@solcreek/adapter-creek/cache-handler")`
|
|
7
|
+
// in their next.config continue to work without changes. New users
|
|
8
|
+
// can wire either path; both resolve to the same module at runtime.
|
|
9
|
+
export { default } from "@solcreek/adapter-core/cache-handler";
|
|
100
10
|
//# sourceMappingURL=cache-handler.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,221 +1,33 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { existsSync
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { applyBaseModifyConfig } from "@solcreek/adapter-core";
|
|
4
5
|
import { handleBuild } from "./build.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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));
|
|
6
|
+
// Dev-fallback path to the cache handler shipped by @solcreek/adapter-core.
|
|
7
|
+
// applyBaseModifyConfig prefers the node_modules-installed copy when one
|
|
8
|
+
// exists (the production path); this resolves the package's own bundled
|
|
9
|
+
// copy as a last resort for the rare case where the adapter is used
|
|
10
|
+
// without `npm install`ing it.
|
|
11
|
+
const coreEntryUrl = new URL("../node_modules/@solcreek/adapter-core/dist/cache-handler.js", import.meta.url);
|
|
12
|
+
const fallbackCacheHandlerPath = existsSync(fileURLToPath(coreEntryUrl))
|
|
13
|
+
? fileURLToPath(coreEntryUrl)
|
|
14
|
+
: path.join(process.cwd(), "node_modules", "@solcreek", "adapter-core", "dist", "cache-handler.js");
|
|
191
15
|
const adapter = {
|
|
192
16
|
name: "adapter-creek",
|
|
193
|
-
modifyConfig(config,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
}
|
|
17
|
+
modifyConfig(config, ctx) {
|
|
18
|
+
// First apply the shared base — auto-transpile, monorepo tracing
|
|
19
|
+
// root, TS error suppression, cache handler wiring.
|
|
20
|
+
const baseConfig = applyBaseModifyConfig(config, ctx, {
|
|
21
|
+
logLabel: "Creek Adapter",
|
|
22
|
+
cacheHandlerPath: fallbackCacheHandlerPath,
|
|
23
|
+
});
|
|
24
|
+
// Then layer CF-Workers-specific knobs on top. These only apply at
|
|
25
|
+
// production build phase; applyBaseModifyConfig is a passthrough
|
|
26
|
+
// for other phases, so guarding here matches its behaviour.
|
|
27
|
+
if (ctx.phase !== "phase-production-build")
|
|
28
|
+
return baseConfig;
|
|
217
29
|
return {
|
|
218
|
-
...
|
|
30
|
+
...baseConfig,
|
|
219
31
|
// Disable memory cache — CF Workers doesn't have persistent fs.
|
|
220
32
|
// The runtime cache handler is inlined in the worker entry (CreekCacheHandler).
|
|
221
33
|
cacheMaxMemorySize: 0,
|
|
@@ -225,18 +37,9 @@ const adapter = {
|
|
|
225
37
|
// → safely under limit. Real PPR fallback shells are typically ≤ a few
|
|
226
38
|
// KB anyway, so this cap is purely defensive.
|
|
227
39
|
experimental: {
|
|
228
|
-
...(
|
|
40
|
+
...(baseConfig.experimental ?? {}),
|
|
229
41
|
maxPostponedStateSize: "20mb",
|
|
230
42
|
},
|
|
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
43
|
};
|
|
241
44
|
},
|
|
242
45
|
async onBuildComplete(ctx) {
|
package/dist/worker-entry.js
CHANGED
|
@@ -333,8 +333,17 @@ if (typeof process !== "undefined") {
|
|
|
333
333
|
}, { bigint: () => BigInt(Math.floor(performance.now() * 1e6)) });
|
|
334
334
|
}
|
|
335
335
|
if (!process.on) process.on = () => process;
|
|
336
|
-
if (!process.removeListener) process.removeListener = () => process;
|
|
337
336
|
if (!process.off) process.off = () => process;
|
|
337
|
+
if (!process.removeListener) process.removeListener = () => process;
|
|
338
|
+
if (!process.removeAllListeners) process.removeAllListeners = () => process;
|
|
339
|
+
if (!process.listeners) process.listeners = () => [];
|
|
340
|
+
if (!process.listenerCount) process.listenerCount = () => 0;
|
|
341
|
+
if (!process.rawListeners) process.rawListeners = () => [];
|
|
342
|
+
if (!process.emit) process.emit = () => false;
|
|
343
|
+
if (!process.prependListener) process.prependListener = () => process;
|
|
344
|
+
if (!process.prependOnceListener) process.prependOnceListener = () => process;
|
|
345
|
+
if (!process.once) process.once = () => process;
|
|
346
|
+
if (!process.addListener) process.addListener = () => process;
|
|
338
347
|
}
|
|
339
348
|
|
|
340
349
|
import { resolveRoutes, responseToMiddlewareResult } from "@next/routing";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solcreek/adapter-creek",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Next.js deployment adapter for Creek (Cloudflare Workers)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@next/routing": "16.2.3",
|
|
48
|
-
"@
|
|
48
|
+
"@solcreek/adapter-core": "^0.1.0",
|
|
49
49
|
"sql.js": "^1.14.1",
|
|
50
50
|
"wrangler": "^4.82.2"
|
|
51
51
|
},
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"next": ">=16.2.3"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
+
"@node-rs/xxhash": "^1.7.6",
|
|
56
57
|
"@types/node": "^22.13.10",
|
|
57
58
|
"miniflare": "^4.20260410.0",
|
|
58
59
|
"next": "16.2.3",
|
package/src/shims/net.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Minimal node:net shim for CF Workers.
|
|
2
|
+
// Only Socket is needed — Next.js passes it to the http shim's
|
|
3
|
+
// IncomingMessage as `socket` but never actually connects.
|
|
4
|
+
|
|
5
|
+
import { EventEmitter } from "node:events";
|
|
6
|
+
|
|
7
|
+
export class Socket extends EventEmitter {
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.writable = true;
|
|
11
|
+
this.readable = true;
|
|
12
|
+
this.encrypted = false;
|
|
13
|
+
this.remoteAddress = "127.0.0.1";
|
|
14
|
+
this.remotePort = 0;
|
|
15
|
+
this.localAddress = "127.0.0.1";
|
|
16
|
+
this.localPort = 0;
|
|
17
|
+
}
|
|
18
|
+
address() { return { address: "127.0.0.1", family: "IPv4", port: 443 }; }
|
|
19
|
+
connect() { return this; }
|
|
20
|
+
write() { return true; }
|
|
21
|
+
end() { this.emit("close"); return this; }
|
|
22
|
+
destroy() { this.emit("close"); return this; }
|
|
23
|
+
setTimeout() { return this; }
|
|
24
|
+
setNoDelay() { return this; }
|
|
25
|
+
setKeepAlive() { return this; }
|
|
26
|
+
ref() { return this; }
|
|
27
|
+
unref() { return this; }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class Server extends EventEmitter {
|
|
31
|
+
constructor() { super(); }
|
|
32
|
+
listen() { return this; }
|
|
33
|
+
close() { return this; }
|
|
34
|
+
address() { return null; }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createServer() { return new Server(); }
|
|
38
|
+
export function createConnection() { return new Socket(); }
|
|
39
|
+
export function connect() { return new Socket(); }
|
|
40
|
+
export function isIP() { return 0; }
|
|
41
|
+
export function isIPv4() { return false; }
|
|
42
|
+
export function isIPv6() { return false; }
|
|
43
|
+
|
|
44
|
+
export default { Socket, Server, createServer, createConnection, connect, isIP, isIPv4, isIPv6 };
|