Skip to content

Commit 6cf1617

Browse files
committed
feat(adapter-cf): initial Cloudflare adapter integration and dev setup
1 parent f5c1dad commit 6cf1617

9 files changed

Lines changed: 1082 additions & 178 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ packages/ui/dist
2626
example/**/wrangler.toml
2727
.wrangler/
2828
.mf/ # Miniflare cache
29+
.miniflare/
2930
.dev.vars # local secrets (DO NOT COMMIT)
31+
.statkapi-cf-tmp/
3032
worker-*.mjs
31-
**/worker-*.mjs
33+
**/worker-*.mjs
34+
wrangler.toml.local
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
export async function paths(){ return [['a','b'], ['guide']]; }
3+
export async function data({ params }){ return { doc: params.slug.join('/') }; }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default { hello: 'world!' };
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export async function paths() {
2+
return ['1', '2', '3', '4', '5', '6'];
3+
}
4+
5+
export async function data({ params }) {
6+
return { id: params.id, extra: 'value' };
7+
}

example/cloudflare/wrangler.example.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ binding = "STATIK_MANIFEST"
1111
id = "REPLACE_ME_KV_NAMESPACE_ID"
1212

1313
[vars]
14-
STATIK_BUILD_TOKEN = "REPLACE_ME_STATIK_BUILD_TOKEN"
14+
STATIK_BUILD_TOKEN = "REPLACE_ME_STATIK_BUILD_TOKEN"
15+
STATIK_SRC = "src-api" # optional: lets the CLI auto-detect

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
"dev": "concurrently -n API,UI -c cyan,magenta \"pnpm -C example/basic dev --no-ui --keep-alive\" \"pnpm -C packages/ui dev\"",
1616
"ui:preview": "pnpm -C packages/ui preview",
1717
"ui:build": "pnpm -C packages/ui build && node packages/cli/scripts/embed-ui.js",
18-
"cf:bundle": "statikapi-cf --src src-api --out dist/worker.mjs",
18+
"cf:bundle": "pnpm --filter @statikapi/adapter-cf exec statikapi-cf --out dist/worker.mjs",
19+
"cf:watch": "pnpm --filter @statikapi/adapter-cf exec statikapi-cf --watch --out dist/worker.mjs",
20+
"cf:dev": "wrangler dev --local",
21+
"cf:dev:all": "concurrently -n BUILD,WRANGLER -c yellow,cyan \"pnpm cf:watch\" \"pnpm cf:dev\"",
1922
"prepublishOnly": "pnpm -r test"
2023
},
2124
"devDependencies": {
@@ -28,7 +31,8 @@
2831
"eslint-plugin-n": "^17.23.1",
2932
"eslint-plugin-promise": "^6.6.0",
3033
"globals": "^16.4.0",
31-
"prettier": "^3.3.3"
34+
"prettier": "^3.3.3",
35+
"wrangler": "^4.47.0"
3236
},
3337
"keywords": [],
3438
"author": "zonayedpca",
Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,88 @@
11
#!/usr/bin/env node
2+
import fs from 'node:fs/promises';
3+
import path from 'node:path';
24
import { bundle } from '../src/node/bundle.js';
35

4-
const args = process.argv.slice(2);
5-
let srcDir = 'src-api';
6-
let outFile = 'dist/worker.mjs';
7-
let prettyDefault = false;
8-
9-
for (let i = 0; i < args.length; i++) {
10-
const a = args[i];
11-
if (a === '--src' && args[i + 1]) {
12-
srcDir = args[++i];
13-
} else if (a === '--out' && args[i + 1]) {
14-
outFile = args[++i];
15-
} else if (a === '--pretty') {
16-
prettyDefault = true;
17-
} else if (a === '--help' || a === '-h') {
18-
console.log(`Usage: statikapi-cf bundle [--src src-api] [--out dist/worker.mjs] [--pretty]`);
19-
process.exit(0);
6+
function parseArgs(argv) {
7+
const out = { srcDir: null, outFile: null, prettyDefault: false, cwd: null, watch: false };
8+
for (let i = 0; i < argv.length; i++) {
9+
const a = argv[i];
10+
if (a === '--src' && argv[i + 1]) out.srcDir = argv[++i];
11+
else if (a === '--out' && argv[i + 1]) out.outFile = argv[++i];
12+
else if (a === '--cwd' && argv[i + 1]) out.cwd = argv[++i];
13+
else if (a === '--pretty') out.prettyDefault = true;
14+
else if (a === '--watch') out.watch = true;
15+
else if (a === '--help' || a === '-h') {
16+
console.log(
17+
`Usage: statikapi-cf [--src src-api] [--out dist/worker.mjs] [--pretty] [--cwd DIR] [--watch]\n` +
18+
`Auto-detects src from wrangler.toml [vars] STATIK_SRC if present.`
19+
);
20+
process.exit(0);
21+
}
2022
}
23+
return out;
2124
}
2225

23-
bundle({ srcDir, outFile, prettyDefault })
24-
.then(() => {
25-
console.log(`✔ worker emitted → ${outFile}`);
26-
})
27-
.catch((e) => {
26+
async function findProjectRoot(start) {
27+
let dir = path.resolve(start);
28+
while (true) {
29+
try {
30+
const f = await fs.readFile(path.join(dir, 'wrangler.toml'), 'utf8');
31+
return { root: dir, wranglerToml: f };
32+
} catch {}
33+
const parent = path.dirname(dir);
34+
if (parent === dir) return { root: path.resolve(start), wranglerToml: null };
35+
dir = parent;
36+
}
37+
}
38+
39+
function readTomlVar(toml, key) {
40+
// tiny parser for [vars] STATIK_SRC = "..."
41+
// keeps it simple and safe; not a full TOML parse
42+
const lines = String(toml || '').split(/\r?\n/);
43+
let inVars = false;
44+
for (const line of lines) {
45+
const l = line.trim();
46+
if (!l || l.startsWith('#')) continue;
47+
if (l.startsWith('[') && l.endsWith(']')) {
48+
inVars = l.toLowerCase() === '[vars]';
49+
continue;
50+
}
51+
if (!inVars) continue;
52+
const m = l.match(/^([A-Za-z0-9_]+)\s*=\s*["']([^"']+)["']/);
53+
if (m && m[1] === key) return m[2];
54+
}
55+
return null;
56+
}
57+
58+
(async function main() {
59+
const args = parseArgs(process.argv.slice(2));
60+
61+
const base = args.cwd || process.cwd();
62+
const { root, wranglerToml } = await findProjectRoot(base);
63+
64+
// Resolve srcDir preference: flag > [vars]STATIK_SRC > env > default
65+
let srcDir =
66+
args.srcDir || readTomlVar(wranglerToml, 'STATIK_SRC') || process.env.STATIK_SRC || 'src-api';
67+
68+
const outFile = args.outFile || 'dist/worker.mjs';
69+
70+
const run = async () => {
71+
await bundle({
72+
cwd: root,
73+
srcDir,
74+
outFile,
75+
prettyDefault: args.prettyDefault,
76+
watch: args.watch,
77+
});
78+
if (!args.watch) console.log(`✔ worker emitted → ${path.relative(root, outFile)}`);
79+
else console.log(`⟲ watcher active — emitting → ${path.relative(root, outFile)}`);
80+
};
81+
82+
try {
83+
await run();
84+
} catch (e) {
2885
console.error(e?.stack || e?.message || String(e));
2986
process.exit(1);
30-
});
87+
}
88+
})();

0 commit comments

Comments
 (0)