@rubriclab/bunl 0.1.25 → 0.2.1

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/bun.lock ADDED
@@ -0,0 +1,169 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "@rubriclab/bunl",
7
+ "dependencies": {
8
+ "@rubriclab/config": "^0.0.24",
9
+ "react": "^19.2.4",
10
+ "react-dom": "^19.2.4",
11
+ },
12
+ "devDependencies": {
13
+ "@rubriclab/package": "^0.0.124",
14
+ "@types/bun": "latest",
15
+ "@types/react": "^19.2.13",
16
+ "@types/react-dom": "^19.2.3",
17
+ },
18
+ },
19
+ },
20
+ "packages": {
21
+ "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
22
+
23
+ "@biomejs/biome": ["@biomejs/biome@2.3.14", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.14", "@biomejs/cli-darwin-x64": "2.3.14", "@biomejs/cli-linux-arm64": "2.3.14", "@biomejs/cli-linux-arm64-musl": "2.3.14", "@biomejs/cli-linux-x64": "2.3.14", "@biomejs/cli-linux-x64-musl": "2.3.14", "@biomejs/cli-win32-arm64": "2.3.14", "@biomejs/cli-win32-x64": "2.3.14" }, "bin": { "biome": "bin/biome" } }, "sha512-QMT6QviX0WqXJCaiqVMiBUCr5WRQ1iFSjvOLoTk6auKukJMvnMzWucXpwZB0e8F00/1/BsS9DzcKgWH+CLqVuA=="],
24
+
25
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UJGPpvWJMkLxSRtpCAKfKh41Q4JJXisvxZL8ChN1eNW3m/WlPFJ6EFDCE7YfUb4XS8ZFi3C1dFpxUJ0Ety5n+A=="],
26
+
27
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-PNkLNQG6RLo8lG7QoWe/hhnMxJIt1tEimoXpGQjwS/dkdNiKBLPv4RpeQl8o3s1OKI3ZOR5XPiYtmbGGHAOnLA=="],
28
+
29
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-KT67FKfzIw6DNnUNdYlBg+eU24Go3n75GWK6NwU4+yJmDYFe9i/MjiI+U/iEzKvo0g7G7MZqoyrhIYuND2w8QQ=="],
30
+
31
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-LInRbXhYujtL3sH2TMCH/UBwJZsoGwfQjBrMfl84CD4hL/41C/EU5mldqf1yoFpsI0iPWuU83U+nB2TUUypWeg=="],
32
+
33
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-ZsZzQsl9U+wxFrGGS4f6UxREUlgHwmEfu1IrXlgNFrNnd5Th6lIJr8KmSzu/+meSa9f4rzFrbEW9LBBA6ScoMA=="],
34
+
35
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-KQU7EkbBBuHPW3/rAcoiVmhlPtDSGOGRPv9js7qJVpYTzjQmVR+C9Rfcz+ti8YCH+zT1J52tuBybtP4IodjxZQ=="],
36
+
37
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-+IKYkj/pUBbnRf1G1+RlyA3LWiDgra1xpS7H2g4BuOzzRbRB+hmlw0yFsLprHhbbt7jUzbzAbAjK/Pn0FDnh1A=="],
38
+
39
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.14", "", { "os": "win32", "cpu": "x64" }, "sha512-oizCjdyQ3WJEswpb3Chdngeat56rIdSYK12JI3iI11Mt5T5EXcZ7WLuowzEaFPNJ3zmOQFliMN8QY1Pi+qsfdQ=="],
40
+
41
+ "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
42
+
43
+ "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
44
+
45
+ "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
46
+
47
+ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
48
+
49
+ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
50
+
51
+ "@rubriclab/cli": ["@rubriclab/cli@0.0.19", "", { "dependencies": { "@rubriclab/config": "*", "@rubriclab/package": "*" }, "peerDependencies": { "zod": "latest" } }, "sha512-Q8s9Gx33aQFQD154g1e1I1CrWv3u474l6hiobldk73IOB8kV42FkoYaXBI6j3QgxxjtfMmtlgz+yHZ6yVkJwAg=="],
52
+
53
+ "@rubriclab/config": ["@rubriclab/config@0.0.24", "", { "dependencies": { "@rubriclab/package": "*" }, "peerDependencies": { "@biomejs/biome": "^2.3.8", "@tailwindcss/postcss": "^4.1.17", "postcss": "^8.5.6", "tailwindcss": "^4.1.17", "typescript": "^5.9.3" } }, "sha512-9i+nj7ESsG/r95SiDtncQG9fZbNKNJrIJDNh09kAAvfKGpGputV6lSsIshr3dBNm8sYl+59u+w5QKilFKilXOA=="],
54
+
55
+ "@rubriclab/package": ["@rubriclab/package@0.0.124", "", { "dependencies": { "@rubriclab/cli": "*", "zod": "latest" }, "bin": { "rubriclab-package": "cli.ts" } }, "sha512-H0xMiWFdrTf/aoEd8hsJ9PfsBhhutROo4+Ryc8TKCjEPky1HFwEUPtD7l/wdaAHbGEGgTQP/8hTn6J0SDOFHIQ=="],
56
+
57
+ "@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="],
58
+
59
+ "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="],
60
+
61
+ "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="],
62
+
63
+ "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="],
64
+
65
+ "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="],
66
+
67
+ "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="],
68
+
69
+ "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="],
70
+
71
+ "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="],
72
+
73
+ "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="],
74
+
75
+ "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="],
76
+
77
+ "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="],
78
+
79
+ "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="],
80
+
81
+ "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="],
82
+
83
+ "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="],
84
+
85
+ "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="],
86
+
87
+ "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
88
+
89
+ "@types/node": ["@types/node@25.2.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg=="],
90
+
91
+ "@types/react": ["@types/react@19.2.13", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ=="],
92
+
93
+ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
94
+
95
+ "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
96
+
97
+ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
98
+
99
+ "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
100
+
101
+ "enhanced-resolve": ["enhanced-resolve@5.19.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="],
102
+
103
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
104
+
105
+ "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
106
+
107
+ "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
108
+
109
+ "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
110
+
111
+ "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
112
+
113
+ "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
114
+
115
+ "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
116
+
117
+ "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
118
+
119
+ "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
120
+
121
+ "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
122
+
123
+ "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
124
+
125
+ "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
126
+
127
+ "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
128
+
129
+ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
130
+
131
+ "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
132
+
133
+ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
134
+
135
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
136
+
137
+ "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
138
+
139
+ "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
140
+
141
+ "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
142
+
143
+ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
144
+
145
+ "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
146
+
147
+ "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
148
+
149
+ "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
150
+
151
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
152
+
153
+ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
154
+
155
+ "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
156
+
157
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
158
+
159
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
160
+
161
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
162
+
163
+ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
164
+
165
+ "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
166
+
167
+ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
168
+ }
169
+ }
package/client.ts CHANGED
@@ -1,96 +1,143 @@
1
- import { parseArgs } from "util";
2
- import browser from "open";
3
- import type { Payload } from "./types";
1
+ import { parseArgs } from 'node:util'
2
+ import type { TunnelInit, TunnelRequest, TunnelResponse } from './types'
3
+ import { fromBase64, openBrowser, page, toBase64 } from './utils'
4
+
5
+ function badGatewayHtml(port: string) {
6
+ return page(
7
+ 'Bad Gateway',
8
+ `<h1>Bad Gateway</h1>
9
+ <p>Could not reach <code>localhost:${port}</code>.</p>
10
+ <p>Make sure your local server is running.</p>`
11
+ )
12
+ }
4
13
 
5
14
  async function main({
6
- port,
7
- domain,
8
- subdomain,
9
- open,
15
+ port,
16
+ domain,
17
+ subdomain,
18
+ open
10
19
  }: {
11
- port?: string;
12
- domain?: string;
13
- subdomain?: string;
14
- open?: boolean;
20
+ port?: string
21
+ domain?: string
22
+ subdomain?: string
23
+ open?: boolean
15
24
  }) {
16
- const params = new URLSearchParams({
17
- new: "",
18
- ...(subdomain ? { subdomain } : {}),
19
- }).toString();
20
- const serverUrl = `ws://${domain}?${params}`;
21
- const socket = new WebSocket(serverUrl);
22
-
23
- const url = `http://localhost:${port}`;
24
-
25
- socket.addEventListener("message", async (event) => {
26
- const data = JSON.parse(event.data as string);
27
-
28
- if (data.url) {
29
- console.log(`\n↪ Your URL: \x1b[32m${data.url}\x1b[0m\n`);
30
- if (open) browser(data.url);
31
- }
32
-
33
- const { method, headers: reqHeaders, pathname, body: reqBody } = data;
34
-
35
- if (method) {
36
- const now = performance.now();
37
- const res = await fetch(`${url}${pathname || ""}`, {
38
- method,
39
- headers: reqHeaders,
40
- body: reqBody,
41
- });
42
-
43
- const elapsed = performance.now() - now;
44
- console.log(
45
- `\x1b[32m${method}\x1b[0m ${pathname} in ${elapsed.toFixed(2)}ms`
46
- );
47
-
48
- const { status, statusText, headers } = res;
49
- const body = await res.text();
50
-
51
- const payload: Payload = {
52
- method,
53
- pathname,
54
- status,
55
- statusText,
56
- headers,
57
- body,
58
- };
59
-
60
- socket.send(JSON.stringify(payload));
61
- }
62
- });
63
-
64
- socket.addEventListener("open", (event: any) => {
65
- if (!event.target.readyState) throw "not ready";
66
- });
67
-
68
- socket.addEventListener("close", () => {
69
- console.warn("server closed connection");
70
- process.exit();
71
- });
25
+ const params = new URLSearchParams({
26
+ new: '',
27
+ ...(subdomain ? { subdomain } : {})
28
+ }).toString()
29
+
30
+ const isLocal = /^(localhost|127\.|0\.0\.0\.0|\[::1\])/.test(domain || '')
31
+ const wsScheme = isLocal ? 'ws' : 'wss'
32
+ const serverUrl = `${wsScheme}://${domain}?${params}`
33
+ const socket = new WebSocket(serverUrl)
34
+ const localHost = Bun.env.HOST || 'localhost'
35
+ const localOrigin = `http://${localHost}:${port}`
36
+
37
+ socket.addEventListener('message', async event => {
38
+ const data = JSON.parse(event.data as string)
39
+
40
+ if (data.type === 'init') {
41
+ const init = data as TunnelInit
42
+ console.log(`\n↪ Your URL: \x1b[32m${init.url}\x1b[0m\n`)
43
+ if (open) openBrowser(init.url)
44
+ return
45
+ }
46
+
47
+ if (data.type === 'request') {
48
+ const req = data as TunnelRequest
49
+ const now = performance.now()
50
+
51
+ try {
52
+ const reqBody =
53
+ req.body && req.method !== 'GET' && req.method !== 'HEAD' ? fromBase64(req.body) : null
54
+
55
+ const fwdHeaders = { ...req.headers }
56
+ delete fwdHeaders.host
57
+ delete fwdHeaders.connection
58
+ delete fwdHeaders['transfer-encoding']
59
+
60
+ const res = await fetch(`${localOrigin}${req.pathname}`, {
61
+ body: reqBody,
62
+ headers: fwdHeaders,
63
+ method: req.method
64
+ })
65
+
66
+ const elapsed = (performance.now() - now).toFixed(1)
67
+ console.log(`\x1b[32m${req.method}\x1b[0m ${req.pathname} → ${res.status} (${elapsed}ms)`)
68
+
69
+ const resBody = await res.arrayBuffer()
70
+ const headers: Record<string, string> = {}
71
+ res.headers.forEach((v, k) => {
72
+ headers[k] = v
73
+ })
74
+
75
+ const response: TunnelResponse = {
76
+ body: toBase64(resBody),
77
+ headers,
78
+ id: req.id,
79
+ status: res.status,
80
+ statusText: res.statusText,
81
+ type: 'response'
82
+ }
83
+
84
+ socket.send(JSON.stringify(response))
85
+ } catch (err) {
86
+ console.error(`\x1b[31mERR\x1b[0m ${req.method} ${req.pathname}: ${err}`)
87
+
88
+ const html = badGatewayHtml(port || '3000')
89
+ const response: TunnelResponse = {
90
+ body: toBase64(new TextEncoder().encode(html).buffer),
91
+ headers: { 'content-type': 'text/html; charset=utf-8' },
92
+ id: req.id,
93
+ status: 502,
94
+ statusText: 'Bad Gateway',
95
+ type: 'response'
96
+ }
97
+ socket.send(JSON.stringify(response))
98
+ }
99
+ }
100
+ })
101
+
102
+ socket.addEventListener('open', () => {
103
+ console.log(`Connected to ${serverUrl}`)
104
+ })
105
+
106
+ socket.addEventListener('close', () => {
107
+ console.warn('Server closed connection')
108
+ process.exit(1)
109
+ })
110
+
111
+ socket.addEventListener('error', err => {
112
+ console.error('WebSocket error:', err)
113
+ process.exit(1)
114
+ })
72
115
  }
73
116
 
74
- /**
75
- * Eg. `bun client.ts -p 3000 -d example.so -s my-subdomain -o`
76
- * > my-subdomain.example.so will be proxied to localhost:3000
77
- * See README for full usage.
78
- */
79
117
  const { values } = parseArgs({
80
- args: process.argv,
81
- options: {
82
- port: { type: "string", short: "p", default: "3000" },
83
- domain: { type: "string", short: "d", default: "localhost:1234" },
84
- subdomain: { type: "string", short: "s" },
85
- open: { type: "boolean", short: "o" },
86
- version: { type: "boolean", short: "v" },
87
- },
88
- allowPositionals: true,
89
- });
118
+ allowPositionals: true,
119
+ args: process.argv,
120
+ options: {
121
+ domain: { default: 'bunl.sh', short: 'd', type: 'string' },
122
+ open: { short: 'o', type: 'boolean' },
123
+ port: { default: '3000', short: 'p', type: 'string' },
124
+ subdomain: { short: 's', type: 'string' },
125
+ version: { short: 'v', type: 'boolean' }
126
+ }
127
+ })
90
128
 
91
129
  if (values.version) {
92
- console.log(process.env.npm_package_version);
93
- process.exit();
130
+ const pkg = await Bun.file(new URL('./package.json', import.meta.url)).json()
131
+ console.log(pkg.version)
132
+ process.exit()
94
133
  }
95
134
 
96
- main(values);
135
+ main({
136
+ domain: values.domain || 'bunl.sh',
137
+ open: values.open || false,
138
+ port: values.port || '3000',
139
+ subdomain: values.subdomain || ''
140
+ }).catch(err => {
141
+ console.error(err)
142
+ process.exit(1)
143
+ })
package/demo.tsx ADDED
@@ -0,0 +1,127 @@
1
+ import { serve } from 'bun'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+
4
+ const port = Number(Bun.env.DEMO_PORT) || 3000
5
+
6
+ const PNG_1PX = Buffer.from(
7
+ 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==',
8
+ 'base64'
9
+ )
10
+
11
+ const FAKE_FONT = (() => {
12
+ const buf = Buffer.alloc(256)
13
+ for (let i = 0; i < 256; i++) buf[i] = i
14
+ return buf
15
+ })()
16
+
17
+ const css = `* {
18
+ margin: 0;
19
+ padding: 0;
20
+ box-sizing: border-box;
21
+ }
22
+
23
+ body {
24
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
25
+ background: #fff;
26
+ color: #000;
27
+ min-height: 100vh;
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ padding: 2rem;
32
+ }
33
+
34
+ main {
35
+ max-width: 480px;
36
+ width: 100%;
37
+ }
38
+
39
+ h1 {
40
+ font-size: 1.5rem;
41
+ font-weight: 600;
42
+ letter-spacing: -0.02em;
43
+ margin-bottom: 1rem;
44
+ }
45
+
46
+ p {
47
+ color: #666;
48
+ margin-bottom: 1.5rem;
49
+ line-height: 1.6;
50
+ }
51
+
52
+ img {
53
+ display: block;
54
+ margin-bottom: 1.5rem;
55
+ border: 1px solid #eee;
56
+ }
57
+
58
+ nav a {
59
+ color: #000;
60
+ text-decoration: none;
61
+ border-bottom: 1px solid #ccc;
62
+ }
63
+
64
+ nav a:hover {
65
+ border-color: #000;
66
+ }
67
+
68
+ nav span {
69
+ color: #ccc;
70
+ margin: 0 0.5rem;
71
+ }`
72
+
73
+ function Page() {
74
+ return (
75
+ <html lang="en">
76
+ <head>
77
+ <meta charSet="utf-8" />
78
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
79
+ <title>bunl</title>
80
+ <link rel="stylesheet" href="/style.css" />
81
+ </head>
82
+ <body>
83
+ <main>
84
+ <h1>bunl</h1>
85
+ <p>Served through a tunnel.</p>
86
+ <img src="/image.png" alt="test" width={100} height={100} />
87
+ <nav>
88
+ <a href="/api/health">API</a>
89
+ <span>·</span>
90
+ <a href="/font.woff2">Font</a>
91
+ </nav>
92
+ </main>
93
+ </body>
94
+ </html>
95
+ )
96
+ }
97
+
98
+ const html = `<!DOCTYPE html>${renderToStaticMarkup(<Page />)}`
99
+
100
+ serve({
101
+ fetch(req) {
102
+ const { pathname } = new URL(req.url)
103
+
104
+ if (pathname === '/style.css')
105
+ return new Response(css, { headers: { 'content-type': 'text/css; charset=utf-8' } })
106
+
107
+ if (pathname === '/image.png')
108
+ return new Response(new Uint8Array(PNG_1PX), { headers: { 'content-type': 'image/png' } })
109
+
110
+ if (pathname === '/font.woff2')
111
+ return new Response(new Uint8Array(FAKE_FONT), { headers: { 'content-type': 'font/woff2' } })
112
+
113
+ if (pathname === '/api/health') return Response.json({ status: 'ok', timestamp: Date.now() })
114
+
115
+ if (pathname === '/echo' && req.method === 'POST')
116
+ return new Response(req.body, {
117
+ headers: {
118
+ 'content-type': req.headers.get('content-type') || 'application/octet-stream'
119
+ }
120
+ })
121
+
122
+ return new Response(html, { headers: { 'content-type': 'text/html; charset=utf-8' } })
123
+ },
124
+ port
125
+ })
126
+
127
+ console.log(`Demo server at http://localhost:${port}`)
@@ -0,0 +1,36 @@
1
+ services:
2
+ server:
3
+ build: .
4
+ ports:
5
+ - "1234:1234"
6
+ volumes:
7
+ - .:/app
8
+ - /app/node_modules
9
+ environment:
10
+ PORT: "1234"
11
+ SCHEME: http
12
+ DOMAIN: "localhost:1234"
13
+ entrypoint: ["bun", "--watch", "run", "server.ts"]
14
+
15
+ demo:
16
+ build: .
17
+ entrypoint: ["bun", "--watch", "run", "demo.ts"]
18
+ ports:
19
+ - "3000:3000"
20
+ volumes:
21
+ - .:/app
22
+ - /app/node_modules
23
+ environment:
24
+ DEMO_PORT: "3000"
25
+
26
+ client:
27
+ build: .
28
+ entrypoint: ["bun", "--watch", "run", "client.ts", "-p", "3000", "-d", "server:1234", "-s", "test"]
29
+ volumes:
30
+ - .:/app
31
+ - /app/node_modules
32
+ depends_on:
33
+ - server
34
+ - demo
35
+ environment:
36
+ HOST: "bunl-demo-1"