bosia 0.9.7 → 0.9.9

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,107 @@
1
+ import { readdirSync, readFileSync } from "fs";
2
+ import { join } from "path";
3
+
4
+ import { toPosix } from "./paths.ts";
5
+
6
+ // Cloudflare Workers has no `Bun` global and no real filesystem, so server code
7
+ // that uses either builds fine and then throws on the first request. This scan
8
+ // fails the workers build first.
9
+ //
10
+ // Scans the user's server files only, by path — a Bun call in a plain
11
+ // src/lib/*.ts helper that a loader imports is missed. Upgrade path: run the
12
+ // check from the workers plugin's onLoad, which sees every bundled file.
13
+
14
+ export interface WorkersGuardHit {
15
+ file: string;
16
+ line: number;
17
+ col: number;
18
+ message: string;
19
+ }
20
+
21
+ const SERVER_FILE = /(^|\/)(hooks\.server\.(ts|js)|\+server\.(ts|js)|\+[^/]*\.server\.(ts|js))$/;
22
+ const LIB_SERVER = /^lib\/server\/.*\.(ts|js)$/;
23
+ const FS_MODULES = new Set(["fs", "node:fs", "fs/promises", "node:fs/promises"]);
24
+
25
+ function isServerFile(rel: string): boolean {
26
+ return (
27
+ (rel.startsWith("routes/") && SERVER_FILE.test(rel)) ||
28
+ rel === "hooks.server.ts" ||
29
+ rel === "hooks.server.js" ||
30
+ LIB_SERVER.test(rel)
31
+ );
32
+ }
33
+
34
+ function badImport(spec: string): string | null {
35
+ if (FS_MODULES.has(spec)) return `imports "${spec}" — Workers has no filesystem`;
36
+ if (spec === "bun" || spec.startsWith("bun:")) return `imports "${spec}" — Bun-only module`;
37
+ return null;
38
+ }
39
+
40
+ export function findWorkersIncompatible(srcDir = "./src"): WorkersGuardHit[] {
41
+ const hits: WorkersGuardHit[] = [];
42
+ let entries: string[];
43
+ try {
44
+ entries = readdirSync(srcDir, { recursive: true }) as string[];
45
+ } catch {
46
+ return hits;
47
+ }
48
+ for (const entry of entries) {
49
+ const rel = toPosix(entry);
50
+ if (!isServerFile(rel)) continue;
51
+ // Posix on every OS, so reports and callers see one path shape.
52
+ const file = toPosix(join(srcDir, entry));
53
+ const source = readFileSync(file, "utf-8");
54
+ const lines = source.split("\n");
55
+
56
+ let imports: { path: string }[] = [];
57
+ try {
58
+ imports = new Bun.Transpiler({ loader: rel.endsWith(".js") ? "js" : "ts" }).scan(
59
+ source,
60
+ ).imports;
61
+ } catch {
62
+ continue; // syntax error — the real build reports it better
63
+ }
64
+ for (const { path } of imports) {
65
+ const message = badImport(path);
66
+ if (!message) continue;
67
+ const quoted = new RegExp(`["']${path.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&")}["']`);
68
+ const i = Math.max(
69
+ 0,
70
+ lines.findIndex((l) => quoted.test(l)),
71
+ );
72
+ hits.push({ file, line: i + 1, col: (lines[i]?.search(quoted) ?? 0) + 1, message });
73
+ }
74
+
75
+ // Line-based, so a `Bun.` inside a string or a multi-line block comment
76
+ // also trips it. `typeof Bun` guards on the same line are allowed.
77
+ lines.forEach((l, i) => {
78
+ const t = l.trimStart();
79
+ if (t.startsWith("//") || t.startsWith("*") || l.includes("typeof Bun")) return;
80
+ const m = /\bBun\.(\w+)/.exec(l);
81
+ if (m)
82
+ hits.push({
83
+ file,
84
+ line: i + 1,
85
+ col: m.index + 1,
86
+ message: `uses Bun.${m[1]} — no Bun global on Workers`,
87
+ });
88
+ });
89
+ }
90
+ return hits;
91
+ }
92
+
93
+ /** Formatted failure text, or null when clean. BOSIA_WORKERS_GUARD=0 downgrades to a warning. */
94
+ export function workersGuardReport(srcDir = "./src"): string | null {
95
+ const hits = findWorkersIncompatible(srcDir);
96
+ if (hits.length === 0) return null;
97
+ const body = hits.map((h) => ` ${h.file}:${h.line}:${h.col} ${h.message}`).join("\n");
98
+ const text =
99
+ `Workers guard: server code uses APIs Cloudflare Workers doesn't have\n\n${body}\n\n` +
100
+ "Use fetch/Web APIs or bindings (event.platform.env) instead. " +
101
+ "Set BOSIA_WORKERS_GUARD=0 to downgrade this to a warning.";
102
+ if (process.env.BOSIA_WORKERS_GUARD === "0") {
103
+ console.warn(`⚠️ ${text}`);
104
+ return null;
105
+ }
106
+ return text;
107
+ }
package/src/lib/index.ts CHANGED
@@ -30,6 +30,8 @@ export type {
30
30
  ResolveFunction,
31
31
  Cookies,
32
32
  CookieOptions,
33
+ Platform,
34
+ PlatformEnv,
33
35
  } from "../core/hooks.ts";
34
36
  export type { CsrfConfig } from "../core/csrf.ts";
35
37
  export type { CorsConfig } from "../core/cors.ts";
@@ -41,4 +43,5 @@ export type {
41
43
  DevContext,
42
44
  RenderContext,
43
45
  BuildTarget,
46
+ RuntimeTarget,
44
47
  } from "../core/types/plugin.ts";
@@ -1,6 +1,7 @@
1
1
  node_modules/
2
2
  dist/
3
3
  .bosia/
4
+ .wrangler/
4
5
  .DS_Store
5
6
  *.log
6
7
 
@@ -10,3 +11,4 @@ public/bosia-tw.css
10
11
  # Local env overrides — never commit secrets
11
12
  .env*.local
12
13
  .env
14
+ .dev.vars*
@@ -1,6 +1,7 @@
1
1
  node_modules/
2
2
  dist/
3
3
  .bosia/
4
+ .wrangler/
4
5
  .DS_Store
5
6
  *.log
6
7
 
@@ -10,3 +11,4 @@ public/bosia-tw.css
10
11
  # Local env overrides — never commit secrets
11
12
  .env*.local
12
13
  .env
14
+ .dev.vars*
@@ -1,6 +1,7 @@
1
1
  node_modules/
2
2
  dist/
3
3
  .bosia/
4
+ .wrangler/
4
5
  .DS_Store
5
6
  *.log
6
7
 
@@ -10,6 +11,7 @@ public/bosia-tw.css
10
11
  # Local env overrides — never commit secrets
11
12
  .env*.local
12
13
  .env
14
+ .dev.vars*
13
15
 
14
16
  # SQLite database artifacts
15
17
  data/*.db*
@@ -1,6 +1,7 @@
1
1
  node_modules/
2
2
  dist/
3
3
  .bosia/
4
+ .wrangler/
4
5
  .DS_Store
5
6
  *.log
6
7
 
@@ -10,6 +11,7 @@ public/bosia-tw.css
10
11
  # Local env overrides — never commit secrets
11
12
  .env*.local
12
13
  .env
14
+ .dev.vars*
13
15
 
14
16
  # SQLite database artifacts
15
17
  data/*.db*