effect-start 0.22.0 → 0.23.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.
Files changed (313) hide show
  1. package/dist/BlobStore.d.ts +80 -0
  2. package/dist/BlobStore.js +19 -0
  3. package/dist/ChildProcess.d.ts +60 -0
  4. package/dist/ChildProcess.js +30 -0
  5. package/dist/Commander.d.ts +3 -6
  6. package/dist/Commander.js +6 -13
  7. package/dist/ContentNegotiation.d.ts +8 -9
  8. package/dist/ContentNegotiation.js +32 -37
  9. package/dist/Cookies.d.ts +47 -0
  10. package/dist/Cookies.js +273 -363
  11. package/dist/Development.d.ts +2 -2
  12. package/dist/Development.js +3 -4
  13. package/dist/Effectify.d.ts +1 -4
  14. package/dist/FilePathPattern.d.ts +3 -3
  15. package/dist/FileRouter.d.ts +5 -8
  16. package/dist/FileRouter.js +9 -10
  17. package/dist/FileRouterCodegen.d.ts +1 -1
  18. package/dist/FileRouterCodegen.js +33 -13
  19. package/dist/FileSystem.d.ts +158 -0
  20. package/dist/FileSystem.js +64 -125
  21. package/dist/Http.js +2 -6
  22. package/dist/PathPattern.d.ts +7 -7
  23. package/dist/PathPattern.js +1 -3
  24. package/dist/PlatformError.d.ts +24 -32
  25. package/dist/PlatformError.js +3 -21
  26. package/dist/PlatformRuntime.js +5 -10
  27. package/dist/Route.d.ts +14 -19
  28. package/dist/Route.js +8 -11
  29. package/dist/RouteBody.d.ts +6 -12
  30. package/dist/RouteBody.js +2 -2
  31. package/dist/RouteError.d.ts +98 -0
  32. package/dist/RouteError.js +55 -0
  33. package/dist/RouteHook.js +6 -11
  34. package/dist/RouteHttp.d.ts +3 -3
  35. package/dist/RouteHttp.js +27 -22
  36. package/dist/RouteMount.d.ts +16 -50
  37. package/dist/RouteMount.js +6 -20
  38. package/dist/RouteSchema.d.ts +22 -1
  39. package/dist/RouteSchema.js +33 -0
  40. package/dist/RouteSse.js +4 -10
  41. package/dist/RouteTree.d.ts +2 -1
  42. package/dist/RouteTree.js +17 -15
  43. package/dist/RouteTrie.d.ts +2 -2
  44. package/dist/RouteTrie.js +4 -9
  45. package/dist/SchemaExtra.d.ts +1 -1
  46. package/dist/Socket.d.ts +27 -0
  47. package/dist/Socket.js +20 -28
  48. package/dist/Sql.d.ts +34 -0
  49. package/dist/Sql.js +5 -0
  50. package/dist/SqlIntrospect.d.ts +91 -0
  51. package/dist/SqlIntrospect.js +466 -0
  52. package/dist/Start.d.ts +4 -6
  53. package/dist/Start.js +10 -2
  54. package/dist/StreamExtra.d.ts +1 -1
  55. package/dist/StreamExtra.js +9 -9
  56. package/dist/System.d.ts +7 -0
  57. package/dist/System.js +22 -0
  58. package/dist/TuplePathPattern.js +55 -50
  59. package/dist/Unique.js +7 -7
  60. package/dist/Values.d.ts +2 -1
  61. package/dist/Values.js +19 -13
  62. package/dist/bun/BunBlobStoreDisk.d.ts +6 -0
  63. package/dist/bun/BunBlobStoreDisk.js +116 -0
  64. package/dist/bun/BunBlobStoreS3.d.ts +11 -0
  65. package/dist/bun/BunBlobStoreS3.js +89 -0
  66. package/dist/bun/BunBlobWatcherDisk.d.ts +6 -0
  67. package/dist/bun/BunBlobWatcherDisk.js +60 -0
  68. package/dist/bun/BunBlobWatcherQueue.d.ts +6 -0
  69. package/dist/bun/BunBlobWatcherQueue.js +17 -0
  70. package/dist/bun/BunBundle.d.ts +5 -6
  71. package/dist/bun/BunBundle.js +7 -15
  72. package/dist/bun/BunChildProcessSpawner.d.ts +3 -0
  73. package/dist/bun/BunChildProcessSpawner.js +103 -0
  74. package/dist/bun/BunImportTrackerPlugin.d.ts +1 -1
  75. package/dist/bun/BunImportTrackerPlugin.js +3 -5
  76. package/dist/bun/BunRoute.d.ts +3 -2
  77. package/dist/bun/BunRoute.js +5 -7
  78. package/dist/bun/BunRuntime.js +1 -1
  79. package/dist/bun/BunServer.d.ts +11 -4
  80. package/dist/bun/BunServer.js +35 -11
  81. package/dist/bun/BunSql.d.ts +4 -0
  82. package/dist/bun/BunSql.js +81 -0
  83. package/dist/bun/_BunEnhancedResolve.d.ts +3 -3
  84. package/dist/bun/_BunEnhancedResolve.js +2 -4
  85. package/dist/bun/index.d.ts +1 -0
  86. package/dist/bun/index.js +1 -0
  87. package/dist/bundler/Bundle.d.ts +2 -1
  88. package/dist/bundler/Bundle.js +1 -1
  89. package/dist/bundler/BundleFiles.d.ts +5 -5
  90. package/dist/bundler/BundleFiles.js +10 -8
  91. package/dist/bundler/BundleRoute.d.ts +27 -0
  92. package/dist/bundler/BundleRoute.js +51 -0
  93. package/dist/client/ScrollState.js +2 -6
  94. package/dist/client/index.js +6 -8
  95. package/dist/console/Console.d.ts +6 -0
  96. package/dist/console/Console.js +26 -0
  97. package/dist/console/ConsoleErrors.d.ts +3 -0
  98. package/dist/console/ConsoleErrors.js +200 -0
  99. package/dist/console/ConsoleLogger.d.ts +3 -0
  100. package/dist/console/ConsoleLogger.js +47 -0
  101. package/dist/console/ConsoleMetrics.d.ts +3 -0
  102. package/dist/console/ConsoleMetrics.js +61 -0
  103. package/dist/console/ConsoleProcess.d.ts +3 -0
  104. package/dist/console/ConsoleProcess.js +49 -0
  105. package/dist/console/ConsoleStore.d.ts +144 -0
  106. package/dist/console/ConsoleStore.js +61 -0
  107. package/dist/console/ConsoleTracer.d.ts +3 -0
  108. package/dist/console/ConsoleTracer.js +94 -0
  109. package/dist/console/Simulation.d.ts +2 -0
  110. package/dist/console/Simulation.js +633 -0
  111. package/dist/console/index.d.ts +3 -0
  112. package/dist/console/index.js +3 -0
  113. package/dist/console/routes/errors/route.d.ts +10 -0
  114. package/dist/console/routes/errors/route.js +47 -0
  115. package/dist/console/routes/fiberDetail.d.ts +16 -0
  116. package/dist/console/routes/fiberDetail.js +38 -0
  117. package/dist/console/routes/fibers/route.d.ts +10 -0
  118. package/dist/console/routes/fibers/route.js +19 -0
  119. package/dist/console/routes/git/route.d.ts +11 -0
  120. package/dist/console/routes/git/route.js +33 -0
  121. package/dist/console/routes/layout.d.ts +9 -0
  122. package/dist/console/routes/layout.js +3 -0
  123. package/dist/console/routes/logs/route.d.ts +10 -0
  124. package/dist/console/routes/logs/route.js +32 -0
  125. package/dist/console/routes/metrics/route.d.ts +10 -0
  126. package/dist/console/routes/metrics/route.js +17 -0
  127. package/dist/console/routes/route.d.ts +6 -0
  128. package/dist/console/routes/route.js +5 -0
  129. package/dist/console/routes/routes/route.d.ts +6 -0
  130. package/dist/console/routes/routes/route.js +20 -0
  131. package/dist/console/routes/services/route.d.ts +6 -0
  132. package/dist/console/routes/services/route.js +12 -0
  133. package/dist/console/routes/system/route.d.ts +10 -0
  134. package/dist/console/routes/system/route.js +18 -0
  135. package/dist/console/routes/traceDetail.d.ts +16 -0
  136. package/dist/console/routes/traceDetail.js +14 -0
  137. package/dist/console/routes/traces/route.d.ts +10 -0
  138. package/dist/console/routes/traces/route.js +39 -0
  139. package/dist/console/routes/tree.d.ts +153 -0
  140. package/dist/console/routes/tree.js +29 -0
  141. package/dist/console/ui/Errors.d.ts +4 -0
  142. package/dist/console/ui/Errors.js +15 -0
  143. package/dist/console/ui/Fibers.d.ts +24 -0
  144. package/dist/console/ui/Fibers.js +121 -0
  145. package/dist/console/ui/Git.d.ts +20 -0
  146. package/dist/console/ui/Git.js +95 -0
  147. package/dist/console/ui/Logs.d.ts +4 -0
  148. package/dist/console/ui/Logs.js +25 -0
  149. package/dist/console/ui/Metrics.d.ts +4 -0
  150. package/dist/console/ui/Metrics.js +26 -0
  151. package/dist/console/ui/Routes.d.ts +8 -0
  152. package/dist/console/ui/Routes.js +70 -0
  153. package/dist/console/ui/Services.d.ts +10 -0
  154. package/dist/console/ui/Services.js +246 -0
  155. package/dist/console/ui/Shell.d.ts +10 -0
  156. package/dist/console/ui/Shell.js +7 -0
  157. package/dist/console/ui/System.d.ts +4 -0
  158. package/dist/console/ui/System.js +35 -0
  159. package/dist/console/ui/Traces.d.ts +12 -0
  160. package/dist/console/ui/Traces.js +179 -0
  161. package/dist/datastar/actions/fetch.d.ts +1 -1
  162. package/dist/datastar/actions/fetch.js +10 -18
  163. package/dist/datastar/actions/peek.js +1 -2
  164. package/dist/datastar/actions/setAll.js +1 -2
  165. package/dist/datastar/actions/toggleAll.js +1 -2
  166. package/dist/datastar/attributes/attr.js +1 -2
  167. package/dist/datastar/attributes/bind.js +10 -18
  168. package/dist/datastar/attributes/class.js +2 -5
  169. package/dist/datastar/attributes/computed.js +2 -3
  170. package/dist/datastar/attributes/effect.js +1 -2
  171. package/dist/datastar/attributes/indicator.js +2 -4
  172. package/dist/datastar/attributes/init.js +2 -3
  173. package/dist/datastar/attributes/jsonSignals.js +1 -2
  174. package/dist/datastar/attributes/on.js +41 -22
  175. package/dist/datastar/attributes/onIntersect.js +2 -3
  176. package/dist/datastar/attributes/onInterval.js +2 -3
  177. package/dist/datastar/attributes/onSignalPatch.js +2 -4
  178. package/dist/datastar/attributes/ref.js +1 -2
  179. package/dist/datastar/attributes/show.js +1 -2
  180. package/dist/datastar/attributes/signals.js +1 -2
  181. package/dist/datastar/attributes/style.js +6 -12
  182. package/dist/datastar/attributes/text.js +1 -2
  183. package/dist/datastar/engine.d.ts +13 -7
  184. package/dist/datastar/engine.js +76 -48
  185. package/dist/datastar/happydom.d.ts +1 -0
  186. package/dist/datastar/happydom.js +8 -0
  187. package/dist/datastar/index.d.ts +1 -1
  188. package/dist/datastar/index.js +1 -1
  189. package/dist/datastar/utils.js +4 -7
  190. package/dist/datastar/watchers/patchElements.js +24 -45
  191. package/dist/datastar/watchers/patchSignals.js +1 -2
  192. package/dist/experimental/EncryptedCookies.d.ts +2 -5
  193. package/dist/experimental/EncryptedCookies.js +17 -48
  194. package/dist/experimental/index.d.ts +0 -1
  195. package/dist/experimental/index.js +0 -1
  196. package/dist/hyper/Hyper.d.ts +2 -9
  197. package/dist/hyper/Hyper.js +1 -12
  198. package/dist/hyper/HyperHtml.d.ts +1 -1
  199. package/dist/hyper/HyperHtml.js +18 -12
  200. package/dist/hyper/HyperHtml.test.d.ts +1 -0
  201. package/dist/hyper/HyperHtml.test.js +197 -0
  202. package/dist/hyper/HyperRoute.test.js +14 -3
  203. package/dist/hyper/html.d.ts +11 -0
  204. package/dist/hyper/html.js +30 -0
  205. package/dist/hyper/index.d.ts +2 -0
  206. package/dist/hyper/index.js +1 -0
  207. package/dist/hyper/jsx-runtime.d.ts +1 -1
  208. package/dist/hyper/jsx-runtime.js +1 -1
  209. package/dist/index.d.ts +1 -0
  210. package/dist/index.js +1 -0
  211. package/dist/lint/plugin.d.ts +86 -0
  212. package/dist/lint/plugin.js +341 -0
  213. package/dist/node/NodeFileSystem.d.ts +2 -2
  214. package/dist/node/NodeFileSystem.js +4 -14
  215. package/dist/sql/bun/index.d.ts +3 -0
  216. package/dist/sql/bun/index.js +75 -0
  217. package/dist/sql/mssql/docker.d.ts +2 -0
  218. package/dist/sql/mssql/docker.js +67 -0
  219. package/dist/sql/mssql/index.d.ts +21 -0
  220. package/dist/sql/mssql/index.js +113 -0
  221. package/dist/testing/TestLogger.js +4 -1
  222. package/dist/testing/index.d.ts +0 -1
  223. package/dist/testing/index.js +0 -1
  224. package/dist/testing/utils.d.ts +3 -3
  225. package/dist/testing/utils.js +4 -4
  226. package/dist/x/cloudflare/CloudflareTunnel.d.ts +2 -5
  227. package/dist/x/cloudflare/CloudflareTunnel.js +14 -27
  228. package/dist/x/datastar/Datastar.d.ts +1 -1
  229. package/dist/x/datastar/Datastar.js +13 -12
  230. package/dist/x/datastar/index.d.ts +1 -2
  231. package/dist/x/datastar/index.js +1 -2
  232. package/dist/x/tailscale/TailscaleTunnel.d.ts +15 -0
  233. package/dist/x/tailscale/TailscaleTunnel.js +68 -0
  234. package/dist/x/tailscale/index.d.ts +1 -0
  235. package/dist/x/tailscale/index.js +1 -0
  236. package/dist/x/tailwind/TailwindPlugin.js +19 -19
  237. package/dist/x/tailwind/compile.d.ts +2 -2
  238. package/dist/x/tailwind/compile.js +2 -4
  239. package/package.json +22 -10
  240. package/src/ChildProcess.ts +145 -0
  241. package/src/PlatformError.ts +27 -50
  242. package/src/Route.ts +2 -2
  243. package/src/RouteError.ts +76 -0
  244. package/src/RouteHttp.ts +13 -5
  245. package/src/RouteSchema.ts +96 -1
  246. package/src/RouteTree.ts +12 -0
  247. package/src/Sql.ts +51 -0
  248. package/src/SqlIntrospect.ts +620 -0
  249. package/src/Start.ts +15 -3
  250. package/src/System.ts +43 -0
  251. package/src/Values.ts +7 -0
  252. package/src/bun/BunChildProcessSpawner.ts +143 -0
  253. package/src/bun/BunRoute.ts +5 -2
  254. package/src/bun/BunServer.ts +22 -1
  255. package/src/bun/index.ts +1 -0
  256. package/src/bundler/BundleRoute.ts +66 -0
  257. package/src/console/Console.ts +42 -0
  258. package/src/console/ConsoleErrors.ts +213 -0
  259. package/src/console/ConsoleLogger.ts +56 -0
  260. package/src/console/ConsoleMetrics.ts +72 -0
  261. package/src/console/ConsoleProcess.ts +59 -0
  262. package/src/console/ConsoleStore.ts +187 -0
  263. package/src/console/ConsoleTracer.ts +107 -0
  264. package/src/console/Simulation.ts +814 -0
  265. package/src/console/console.html +340 -0
  266. package/src/console/index.ts +3 -0
  267. package/src/console/routes/errors/route.tsx +97 -0
  268. package/src/console/routes/fiberDetail.tsx +54 -0
  269. package/src/console/routes/fibers/route.tsx +45 -0
  270. package/src/console/routes/git/route.tsx +64 -0
  271. package/src/console/routes/layout.tsx +4 -0
  272. package/src/console/routes/logs/route.tsx +77 -0
  273. package/src/console/routes/metrics/route.tsx +36 -0
  274. package/src/console/routes/route.tsx +8 -0
  275. package/src/console/routes/routes/route.tsx +30 -0
  276. package/src/console/routes/services/route.tsx +21 -0
  277. package/src/console/routes/system/route.tsx +43 -0
  278. package/src/console/routes/traceDetail.tsx +22 -0
  279. package/src/console/routes/traces/route.tsx +81 -0
  280. package/src/console/routes/tree.ts +30 -0
  281. package/src/console/ui/Errors.tsx +76 -0
  282. package/src/console/ui/Fibers.tsx +321 -0
  283. package/src/console/ui/Git.tsx +182 -0
  284. package/src/console/ui/Logs.tsx +46 -0
  285. package/src/console/ui/Metrics.tsx +78 -0
  286. package/src/console/ui/Routes.tsx +125 -0
  287. package/src/console/ui/Services.tsx +273 -0
  288. package/src/console/ui/Shell.tsx +62 -0
  289. package/src/console/ui/System.tsx +131 -0
  290. package/src/console/ui/Traces.tsx +426 -0
  291. package/src/datastar/README.md +6 -1
  292. package/src/datastar/actions/fetch.ts +0 -1
  293. package/src/datastar/attributes/on.ts +40 -20
  294. package/src/datastar/engine.ts +51 -0
  295. package/src/datastar/jsx.d.ts +79 -0
  296. package/src/hyper/Hyper.ts +1 -16
  297. package/src/hyper/HyperHtml.ts +6 -4
  298. package/src/hyper/HyperRoute.ts +2 -1
  299. package/src/hyper/html.ts +47 -0
  300. package/src/hyper/index.ts +2 -0
  301. package/src/hyper/jsx.d.ts +5 -3
  302. package/src/index.ts +1 -0
  303. package/src/lint/plugin.js +129 -0
  304. package/src/sql/bun/index.ts +147 -0
  305. package/src/sql/mssql/docker.ts +117 -0
  306. package/src/sql/mssql/index.ts +223 -0
  307. package/src/sql/mssql/mssql.d.ts +41 -0
  308. package/src/x/cloudflare/CloudflareTunnel.ts +8 -36
  309. package/src/x/tailscale/TailscaleTunnel.ts +113 -0
  310. package/src/x/tailscale/index.ts +1 -0
  311. package/src/x/datastar/Datastar.ts +0 -61
  312. package/src/x/datastar/index.ts +0 -2
  313. package/src/x/datastar/jsx-datastar.d.ts +0 -60
package/dist/System.js ADDED
@@ -0,0 +1,22 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as ChildProcess from "./ChildProcess.js";
3
+ import * as PlatformError from "./PlatformError.js";
4
+ export const cwd = Effect.sync(() => process.cwd());
5
+ export const which = (name) => Effect.flatMap(Effect.try({
6
+ try: () => Bun.which(name),
7
+ catch: (err) => new PlatformError.SystemError({
8
+ reason: "Unknown",
9
+ module: "System",
10
+ method: "which",
11
+ description: err instanceof Error ? err.message : `Failed to look up "${name}"`,
12
+ cause: err,
13
+ }),
14
+ }), (path) => path === null
15
+ ? Effect.fail(new PlatformError.SystemError({
16
+ reason: "NotFound",
17
+ module: "System",
18
+ method: "which",
19
+ description: `Executable not found: "${name}"`,
20
+ }))
21
+ : Effect.succeed(path));
22
+ export const spawn = (command, args, options) => ChildProcess.spawn(ChildProcess.make(command, args, options));
@@ -1,63 +1,68 @@
1
1
  export function format(tuple) {
2
- return "/" + tuple
3
- .map((el) => {
4
- if (typeof el === "string")
5
- return el;
6
- if (Array.isArray(el[0]))
7
- return "[[" + el[0][0] + "]]";
8
- const [name, suffix, prefix] = el;
9
- return (prefix ?? "") + "[" + name + "]" + (suffix ?? "");
10
- })
11
- .join("/");
2
+ return ("/" +
3
+ tuple
4
+ .map((el) => {
5
+ if (typeof el === "string")
6
+ return el;
7
+ if (Array.isArray(el[0]))
8
+ return "[[" + el[0][0] + "]]";
9
+ const [name, suffix, prefix] = el;
10
+ return (prefix ?? "") + "[" + name + "]" + (suffix ?? "");
11
+ })
12
+ .join("/"));
12
13
  }
13
14
  export function toColon(tuple) {
14
- return "/" + tuple
15
- .map((el) => {
16
- if (typeof el === "string")
17
- return el;
18
- if (Array.isArray(el[0]))
19
- return "*";
20
- const [name, suffix, prefix] = el;
21
- return (prefix ?? "") + ":" + name + (suffix ?? "");
22
- })
23
- .join("/");
15
+ return ("/" +
16
+ tuple
17
+ .map((el) => {
18
+ if (typeof el === "string")
19
+ return el;
20
+ if (Array.isArray(el[0]))
21
+ return "*";
22
+ const [name, suffix, prefix] = el;
23
+ return (prefix ?? "") + ":" + name + (suffix ?? "");
24
+ })
25
+ .join("/"));
24
26
  }
25
27
  export const toHono = toColon;
26
28
  export function toExpress(tuple) {
27
- return "/" + tuple
28
- .map((el) => {
29
- if (typeof el === "string")
30
- return el;
31
- if (Array.isArray(el[0]))
32
- return "*" + el[0][0];
33
- const [name, suffix, prefix] = el;
34
- return (prefix ?? "") + ":" + name + (suffix ?? "");
35
- })
36
- .join("/");
29
+ return ("/" +
30
+ tuple
31
+ .map((el) => {
32
+ if (typeof el === "string")
33
+ return el;
34
+ if (Array.isArray(el[0]))
35
+ return "*" + el[0][0];
36
+ const [name, suffix, prefix] = el;
37
+ return (prefix ?? "") + ":" + name + (suffix ?? "");
38
+ })
39
+ .join("/"));
37
40
  }
38
41
  export const toEffect = toColon;
39
42
  export function toURLPattern(tuple) {
40
- return "/" + tuple
41
- .map((el) => {
42
- if (typeof el === "string")
43
- return el;
44
- if (Array.isArray(el[0]))
45
- return ":" + el[0][0] + "+";
46
- const [name, suffix, prefix] = el;
47
- return (prefix ?? "") + ":" + name + (suffix ?? "");
48
- })
49
- .join("/");
43
+ return ("/" +
44
+ tuple
45
+ .map((el) => {
46
+ if (typeof el === "string")
47
+ return el;
48
+ if (Array.isArray(el[0]))
49
+ return ":" + el[0][0] + "+";
50
+ const [name, suffix, prefix] = el;
51
+ return (prefix ?? "") + ":" + name + (suffix ?? "");
52
+ })
53
+ .join("/"));
50
54
  }
51
55
  export function toRemix(tuple) {
52
- return "/" + tuple
53
- .map((el) => {
54
- if (typeof el === "string")
55
- return el;
56
- if (Array.isArray(el[0]))
57
- return "$";
58
- const [name, suffix, prefix] = el;
59
- return (prefix ?? "") + "$" + name + (suffix ?? "");
60
- })
61
- .join("/");
56
+ return ("/" +
57
+ tuple
58
+ .map((el) => {
59
+ if (typeof el === "string")
60
+ return el;
61
+ if (Array.isArray(el[0]))
62
+ return "$";
63
+ const [name, suffix, prefix] = el;
64
+ return (prefix ?? "") + "$" + name + (suffix ?? "");
65
+ })
66
+ .join("/"));
62
67
  }
63
68
  export const toBun = toColon;
package/dist/Unique.js CHANGED
@@ -54,12 +54,12 @@ function uuid4bytes() {
54
54
  export function toTimestamp(bytes) {
55
55
  if (bytes.length < 6)
56
56
  return 0;
57
- return (bytes[0] * 0x10000000000
58
- + bytes[1] * 0x100000000
59
- + bytes[2] * 0x1000000
60
- + bytes[3] * 0x10000
61
- + bytes[4] * 0x100
62
- + bytes[5]);
57
+ return (bytes[0] * 0x10000000000 +
58
+ bytes[1] * 0x100000000 +
59
+ bytes[2] * 0x1000000 +
60
+ bytes[3] * 0x10000 +
61
+ bytes[4] * 0x100 +
62
+ bytes[5]);
63
63
  }
64
64
  export function uuid7Bytes(time = Date.now()) {
65
65
  const buf = new Uint8Array(16);
@@ -124,7 +124,7 @@ function formatUlid(bytes) {
124
124
  }
125
125
  function encodeUlidTime(time) {
126
126
  let value = BigInt(time);
127
- const result = new Array(10);
127
+ const result = Array.from({ length: 10 });
128
128
  for (let i = 9; i >= 0; i--) {
129
129
  result[i] = ALPHABET_BASE32_CROCKFORD[Number(value & 31n)];
130
130
  value >>= 5n;
package/dist/Values.d.ts CHANGED
@@ -12,7 +12,7 @@ export declare function isPlainObject(value: unknown): value is Record<string, u
12
12
  * class instances or objects with methods.
13
13
  */
14
14
  type HasMethod<T> = {
15
- [K in keyof T]: T[K] extends (...args: any[]) => any ? true : never;
15
+ [K in keyof T]: T[K] extends (...args: Array<any>) => any ? true : never;
16
16
  }[keyof T];
17
17
  export type IsPlainObject<T> = T extends object ? T extends Function ? false : HasMethod<T> extends never ? true : false : false;
18
18
  export type Simplify<T> = {
@@ -22,5 +22,6 @@ export type Simplify<T> = {
22
22
  } extends infer U ? {
23
23
  [K in keyof U]: U[K];
24
24
  } : never;
25
+ export declare const firstValue: <T>(record: Record<string, T>) => T | undefined;
25
26
  export declare const concatBytes: (a: Uint8Array, b: Uint8Array) => Uint8Array;
26
27
  export {};
package/dist/Values.js CHANGED
@@ -3,25 +3,31 @@ export function isPlainObject(value) {
3
3
  return false;
4
4
  }
5
5
  // Check for built-in types and web APIs
6
- if (ArrayBuffer.isView(value)
7
- || value instanceof ArrayBuffer
8
- || value instanceof Blob
9
- || value instanceof FormData
10
- || value instanceof URLSearchParams
11
- || value instanceof ReadableStream
12
- || value instanceof Date
13
- || value instanceof Map
14
- || value instanceof Set
15
- || value instanceof RegExp
16
- || value instanceof Error
17
- || value instanceof Promise
18
- || Array.isArray(value)) {
6
+ if (ArrayBuffer.isView(value) ||
7
+ value instanceof ArrayBuffer ||
8
+ value instanceof Blob ||
9
+ value instanceof FormData ||
10
+ value instanceof URLSearchParams ||
11
+ value instanceof ReadableStream ||
12
+ value instanceof Date ||
13
+ value instanceof Map ||
14
+ value instanceof Set ||
15
+ value instanceof RegExp ||
16
+ value instanceof Error ||
17
+ value instanceof Promise ||
18
+ Array.isArray(value)) {
19
19
  return false;
20
20
  }
21
21
  // Check if it's a plain object (Object.prototype or null prototype)
22
22
  const proto = Object.getPrototypeOf(value);
23
23
  return proto === null || proto === Object.prototype;
24
24
  }
25
+ export const firstValue = (record) => {
26
+ for (const key in record) {
27
+ return record[key];
28
+ }
29
+ return undefined;
30
+ };
25
31
  export const concatBytes = (a, b) => {
26
32
  const result = new Uint8Array(a.byteLength + b.byteLength);
27
33
  result.set(a);
@@ -0,0 +1,6 @@
1
+ import * as Layer from "effect/Layer";
2
+ import { BlobStore as BlobStoreTag } from "../BlobStore.ts";
3
+ export interface DiskConfig {
4
+ readonly directory?: string;
5
+ }
6
+ export declare const layer: (config?: DiskConfig) => Layer.Layer<BlobStoreTag>;
@@ -0,0 +1,116 @@
1
+ import * as Chunk from "effect/Chunk";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import * as Option from "effect/Option";
5
+ import * as Stream from "effect/Stream";
6
+ import * as NFS from "node:fs";
7
+ import * as NPath from "node:path";
8
+ import { BlobStore as BlobStoreTag } from "../BlobStore.js";
9
+ import * as PlatformError from "../PlatformError.js";
10
+ import { handleErrnoException } from "../node/NodeFileSystem.js";
11
+ const handleBadArgument = (method) => (cause) => new PlatformError.BadArgument({
12
+ module: "BlobStore",
13
+ method,
14
+ cause,
15
+ });
16
+ const handleErrno = (method) => handleErrnoException("BlobStore", method);
17
+ const tryPromise = (method, path, promise) => Effect.tryPromise({
18
+ try: promise,
19
+ catch: (err) => {
20
+ if (err instanceof Error && "code" in err) {
21
+ return handleErrno(method)(err, [path]);
22
+ }
23
+ return handleBadArgument(method)(err);
24
+ },
25
+ });
26
+ const validatePath = (directory, key) => {
27
+ const resolved = NPath.resolve(directory, key);
28
+ const root = NPath.resolve(directory);
29
+ if (resolved !== root && !resolved.startsWith(root + NPath.sep)) {
30
+ return Effect.fail(new PlatformError.BadArgument({
31
+ module: "BlobStore",
32
+ method: "ref",
33
+ description: `Path traversal: key "${key}" escapes directory "${directory}"`,
34
+ }));
35
+ }
36
+ return Effect.succeed(resolved);
37
+ };
38
+ const makeRef = (directory, path, key, begin, end) => {
39
+ const getFile = () => {
40
+ const f = Bun.file(path);
41
+ return begin !== undefined || end !== undefined ? f.slice(begin, end) : f;
42
+ };
43
+ return {
44
+ key,
45
+ bytes: tryPromise("bytes", path, () => getFile().bytes()),
46
+ text: tryPromise("text", path, () => getFile().text()),
47
+ json: tryPromise("json", path, () => getFile().json()),
48
+ stat: Effect.flatMap(tryPromise("stat", path, () => Bun.file(path).stat()), (s) => Effect.succeed({
49
+ size: s.size,
50
+ lastModified: Option.fromNullable(s.mtime),
51
+ etag: Option.none(),
52
+ type: Option.fromNullable(Bun.file(path).type || null),
53
+ })),
54
+ exists: tryPromise("exists", path, () => Bun.file(path).exists()),
55
+ delete: tryPromise("delete", path, () => NFS.promises.unlink(path)),
56
+ stream: Stream.fromReadableStream(() => getFile().stream(), (err) => {
57
+ if (err instanceof Error && "code" in err) {
58
+ return handleErrno("stream")(err, [path]);
59
+ }
60
+ return handleBadArgument("stream")(err);
61
+ }),
62
+ write: (data) => tryPromise("write", path, () => Bun.write(path, data, { createPath: true }).then(() => undefined)),
63
+ slice: (b, e) => makeRef(directory, path, key, b, e),
64
+ };
65
+ };
66
+ const listEntries = (directory, options) => {
67
+ const baseDir = options?.prefix
68
+ ? NPath.join(directory, options.prefix)
69
+ : directory;
70
+ return Stream.fromEffect(Effect.tryPromise({
71
+ try: async () => {
72
+ try {
73
+ const entries = await NFS.promises.readdir(baseDir, {
74
+ recursive: true,
75
+ withFileTypes: true,
76
+ });
77
+ return entries
78
+ .filter((e) => e.isFile())
79
+ .map((e) => {
80
+ const rel = NPath.join(e.parentPath, e.name);
81
+ const key = NPath.relative(directory, rel);
82
+ return {
83
+ key,
84
+ size: Option.none(),
85
+ lastModified: Option.none(),
86
+ etag: Option.none(),
87
+ };
88
+ });
89
+ }
90
+ catch (err) {
91
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
92
+ return [];
93
+ }
94
+ throw err;
95
+ }
96
+ },
97
+ catch: (err) => {
98
+ if (err instanceof Error && "code" in err) {
99
+ return handleErrno("list")(err, [baseDir]);
100
+ }
101
+ return handleBadArgument("list")(err);
102
+ },
103
+ })).pipe(Stream.flatMap((entries) => Stream.fromChunk(Chunk.fromIterable(entries))));
104
+ };
105
+ export const layer = (config) => {
106
+ const directory = config?.directory ?? "/";
107
+ return Layer.succeed(BlobStoreTag, {
108
+ ref: (key) => Effect.map(validatePath(directory, key), (path) => makeRef(directory, path, key)),
109
+ list: (options) => listEntries(directory, options),
110
+ presign: (_key, _options) => Effect.fail(new PlatformError.BadArgument({
111
+ module: "BlobStore",
112
+ method: "presign",
113
+ description: "Presigned URLs are not supported for disk storage",
114
+ })),
115
+ });
116
+ };
@@ -0,0 +1,11 @@
1
+ import * as Layer from "effect/Layer";
2
+ import { BlobStore as BlobStoreTag } from "../BlobStore.ts";
3
+ export interface S3Config {
4
+ readonly bucket?: string;
5
+ readonly endpoint?: string;
6
+ readonly region?: string;
7
+ readonly accessKeyId?: string;
8
+ readonly secretAccessKey?: string;
9
+ readonly sessionToken?: string;
10
+ }
11
+ export declare const layer: (config?: S3Config) => Layer.Layer<BlobStoreTag>;
@@ -0,0 +1,89 @@
1
+ import * as Chunk from "effect/Chunk";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import * as Option from "effect/Option";
5
+ import * as Stream from "effect/Stream";
6
+ import { BlobStore as BlobStoreTag } from "../BlobStore.js";
7
+ import * as PlatformError from "../PlatformError.js";
8
+ const handleError = (method) => (err) => {
9
+ if (err instanceof Error) {
10
+ const msg = err.message.toLowerCase();
11
+ let reason = "Unknown";
12
+ if (msg.includes("nosuchkey") || msg.includes("not found") || msg.includes("404")) {
13
+ reason = "NotFound";
14
+ }
15
+ else if (msg.includes("forbidden") || msg.includes("403") || msg.includes("access denied")) {
16
+ reason = "PermissionDenied";
17
+ }
18
+ return new PlatformError.SystemError({
19
+ reason,
20
+ module: "BlobStore",
21
+ method,
22
+ description: err.message,
23
+ cause: err,
24
+ });
25
+ }
26
+ return new PlatformError.BadArgument({
27
+ module: "BlobStore",
28
+ method,
29
+ cause: err,
30
+ });
31
+ };
32
+ const tryPromise = (method, promise) => Effect.tryPromise({
33
+ try: promise,
34
+ catch: handleError(method),
35
+ });
36
+ const makeRef = (client, key, begin, end) => {
37
+ const getFile = () => {
38
+ const f = client.file(key);
39
+ return begin !== undefined || end !== undefined ? f.slice(begin, end) : f;
40
+ };
41
+ return {
42
+ key,
43
+ bytes: tryPromise("bytes", () => getFile().bytes()),
44
+ text: tryPromise("text", () => getFile().text()),
45
+ json: tryPromise("json", () => getFile().json()),
46
+ stat: tryPromise("stat", () => client.file(key).stat()).pipe(Effect.map((s) => ({
47
+ size: s.size,
48
+ lastModified: Option.some(s.lastModified),
49
+ etag: Option.some(s.etag),
50
+ type: Option.fromNullable(s.type || null),
51
+ }))),
52
+ exists: tryPromise("exists", () => client.file(key).exists()),
53
+ delete: tryPromise("delete", () => client.file(key).delete()),
54
+ stream: Stream.fromReadableStream(() => getFile().stream(), handleError("stream")),
55
+ write: (data) => tryPromise("write", () => client.file(key).write(data).then(() => undefined)),
56
+ slice: (b, e) => makeRef(client, key, b, e),
57
+ };
58
+ };
59
+ const listEntries = (client, options) => Stream.paginateChunkEffect(undefined, (cursor) => tryPromise("list", () => client.list({
60
+ prefix: options?.prefix,
61
+ ...(cursor ? { startAfter: cursor } : {}),
62
+ })).pipe(Effect.map((response) => {
63
+ const entries = (response.contents ?? []).map((item) => ({
64
+ key: item.key,
65
+ size: Option.fromNullable(item.size),
66
+ lastModified: Option.fromNullable(item.lastModified ? new Date(item.lastModified) : undefined),
67
+ etag: Option.fromNullable(item.eTag),
68
+ }));
69
+ const chunk = Chunk.fromIterable(entries);
70
+ const last = entries[entries.length - 1];
71
+ const next = response.isTruncated && last
72
+ ? Option.some(last.key)
73
+ : Option.none();
74
+ return [chunk, next];
75
+ })));
76
+ export const layer = (config) => {
77
+ const client = new Bun.S3Client(config);
78
+ return Layer.succeed(BlobStoreTag, {
79
+ ref: (key) => Effect.succeed(makeRef(client, key)),
80
+ list: (options) => listEntries(client, options),
81
+ presign: (key, options) => Effect.try({
82
+ try: () => client.presign(key, {
83
+ expiresIn: options?.expiresIn,
84
+ method: options?.method,
85
+ }),
86
+ catch: handleError("presign"),
87
+ }),
88
+ });
89
+ };
@@ -0,0 +1,6 @@
1
+ import * as Layer from "effect/Layer";
2
+ import * as BlobStore from "../BlobStore.ts";
3
+ export interface DiskWatcherConfig {
4
+ readonly directory: string;
5
+ }
6
+ export declare const layer: (config: DiskWatcherConfig) => Layer.Layer<BlobStore.BlobWatcher>;
@@ -0,0 +1,60 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import * as Stream from "effect/Stream";
4
+ import * as NFS from "node:fs";
5
+ import * as NPath from "node:path";
6
+ import * as BlobStore from "../BlobStore.js";
7
+ import * as PlatformError from "../PlatformError.js";
8
+ const watchDir = (directory, options) => {
9
+ const watchPath = options?.prefix
10
+ ? NPath.join(directory, options.prefix)
11
+ : directory;
12
+ return Stream.asyncScoped((emit) => Effect.acquireRelease(Effect.sync(() => {
13
+ const watcher = NFS.watch(watchPath, { recursive: true }, (event, filename) => {
14
+ if (!filename)
15
+ return;
16
+ const key = options?.prefix
17
+ ? NPath.join(options.prefix, filename)
18
+ : filename;
19
+ switch (event) {
20
+ case "rename": {
21
+ const fullPath = NPath.join(directory, key);
22
+ emit.fromEffect(Effect.tryPromise({
23
+ try: () => Bun.file(fullPath).exists(),
24
+ catch: () => new PlatformError.SystemError({
25
+ reason: "Unknown",
26
+ module: "BlobWatcher",
27
+ method: "watch",
28
+ pathOrDescriptor: fullPath,
29
+ }),
30
+ }).pipe(Effect.map((exists) => exists
31
+ ? new BlobStore.WatchEventCreated({ key })
32
+ : new BlobStore.WatchEventDeleted({ key }))));
33
+ return;
34
+ }
35
+ case "change": {
36
+ emit.single(new BlobStore.WatchEventUpdated({ key }));
37
+ return;
38
+ }
39
+ }
40
+ });
41
+ watcher.on("error", (error) => {
42
+ emit.fail(new PlatformError.SystemError({
43
+ module: "BlobWatcher",
44
+ reason: "Unknown",
45
+ method: "watch",
46
+ pathOrDescriptor: watchPath,
47
+ cause: error,
48
+ }));
49
+ });
50
+ return watcher;
51
+ }), (watcher) => Effect.sync(() => watcher.close())));
52
+ };
53
+ export const layer = (config) => Layer.succeed(BlobStore.BlobWatcher, {
54
+ watch: (options) => watchDir(config.directory, options),
55
+ notify: (_event) => Effect.fail(new PlatformError.BadArgument({
56
+ module: "BlobWatcher",
57
+ method: "notify",
58
+ description: "Disk watcher receives events from the OS, not from notify()",
59
+ })),
60
+ });
@@ -0,0 +1,6 @@
1
+ import * as Layer from "effect/Layer";
2
+ import * as BlobStore from "../BlobStore.ts";
3
+ export interface QueueWatcherConfig {
4
+ readonly capacity?: number;
5
+ }
6
+ export declare const layer: (config?: QueueWatcherConfig) => Layer.Layer<BlobStore.BlobWatcher, never, never>;
@@ -0,0 +1,17 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import * as Queue from "effect/Queue";
4
+ import * as Stream from "effect/Stream";
5
+ import * as BlobStore from "../BlobStore.js";
6
+ export const layer = (config) => Layer.scoped(BlobStore.BlobWatcher, Effect.gen(function* () {
7
+ const queue = yield* Queue.bounded(config?.capacity ?? 1024);
8
+ return {
9
+ watch: (options) => {
10
+ const stream = Stream.fromQueue(queue);
11
+ if (!options?.prefix)
12
+ return stream;
13
+ return stream.pipe(Stream.filter((event) => event.key.startsWith(options.prefix)));
14
+ },
15
+ notify: (event) => Queue.offer(queue, event),
16
+ };
17
+ }));
@@ -1,12 +1,11 @@
1
1
  import type { BuildConfig } from "bun";
2
- import { Context, Effect, Layer } from "effect";
3
- import type { BundleContext } from "../bundler/Bundle.ts";
2
+ import { type Context, Effect, Layer } from "effect";
4
3
  import * as Bundle from "../bundler/Bundle.ts";
5
4
  export type BuildOptions = Omit<BuildConfig, "outdir">;
6
- export declare const buildClient: (config: BuildOptions | string) => Effect.Effect<BundleContext, Bundle.BundleError, never>;
7
- export declare const buildServer: (config: BuildOptions | string) => Effect.Effect<BundleContext, Bundle.BundleError, never>;
5
+ export declare const buildClient: (config: BuildOptions | string) => Effect.Effect<Bundle.BundleContext, Bundle.BundleError, never>;
6
+ export declare const buildServer: (config: BuildOptions | string) => Effect.Effect<Bundle.BundleContext, Bundle.BundleError, never>;
8
7
  /**
9
8
  * Given a config, build a bundle and returns every time when effect is executed.
10
9
  */
11
- export declare function build(config: BuildOptions): Effect.Effect<BundleContext, Bundle.BundleError>;
12
- export declare function layer<T>(tag: Context.Tag<T, BundleContext>, config: BuildOptions): Layer.Layer<T, Bundle.BundleError, never>;
10
+ export declare function build(config: BuildOptions): Effect.Effect<Bundle.BundleContext, Bundle.BundleError>;
11
+ export declare function layer<T>(tag: Context.Tag<T, Bundle.BundleContext>, config: BuildOptions): Layer.Layer<T, Bundle.BundleError, never>;
@@ -1,4 +1,4 @@
1
- import { Array, Effect, Iterable, Layer, pipe, Record, } from "effect";
1
+ import { Array, Effect, Iterable, Layer, pipe, Record } from "effect";
2
2
  import * as NPath from "node:path";
3
3
  import * as Bundle from "../bundler/Bundle.js";
4
4
  export const buildClient = (config) => {
@@ -58,9 +58,7 @@ export function build(config) {
58
58
  return manifest.entrypoints[path] ?? null;
59
59
  };
60
60
  const getArtifact = (path) => {
61
- return artifactsMap[resolve(path)]
62
- ?? artifactsMap[path]
63
- ?? null;
61
+ return artifactsMap[resolve(path)] ?? artifactsMap[path] ?? null;
64
62
  };
65
63
  return {
66
64
  ...manifest,
@@ -81,9 +79,9 @@ function getBaseDir(paths) {
81
79
  if (paths.length === 1)
82
80
  return NPath.dirname(paths[0]);
83
81
  const segmentsList = paths.map((path) => NPath.dirname(path).split("/").filter(Boolean));
84
- return segmentsList[0]
82
+ return (segmentsList[0]
85
83
  .filter((segment, i) => segmentsList.every((segs) => segs[i] === segment))
86
- .reduce((path, seg) => `${path}/${seg}`, "") ?? "";
84
+ .reduce((path, seg) => `${path}/${seg}`, "") ?? "");
87
85
  }
88
86
  /**
89
87
  * Maps entrypoints to their respective build artifacts.
@@ -93,8 +91,7 @@ function joinBuildEntrypoints(options, output) {
93
91
  const commonPathPrefix = getBaseDir(options.entrypoints) + "/";
94
92
  return pipe(Iterable.zip(options.entrypoints, pipe(output.outputs,
95
93
  // Filter out source maps to properly map artifacts to entrypoints.
96
- Iterable.filter((v) => v.kind !== "sourcemap"
97
- && !(v.loader === "html" && v.path.endsWith(".js"))))), Iterable.map(([entrypoint, artifact]) => {
94
+ Iterable.filter((v) => v.kind !== "sourcemap" && !(v.loader === "html" && v.path.endsWith(".js"))))), Iterable.map(([entrypoint, artifact]) => {
98
95
  return {
99
96
  shortPath: entrypoint.replace(commonPathPrefix, ""),
100
97
  fullPath: entrypoint,
@@ -109,10 +106,7 @@ function joinBuildEntrypoints(options, output) {
109
106
  function generateManifestfromBunBundle(options, output, imports) {
110
107
  const entrypointArtifacts = joinBuildEntrypoints(options, output);
111
108
  return {
112
- entrypoints: pipe(entrypointArtifacts, Iterable.map((v) => [
113
- v.shortPath,
114
- v.artifact.path.replace(/^\.\//, ""),
115
- ]), Record.fromEntries),
109
+ entrypoints: pipe(entrypointArtifacts, Iterable.map((v) => [v.shortPath, v.artifact.path.replace(/^\.\//, "")]), Record.fromEntries),
116
110
  artifacts: pipe(output.outputs, Iterable.map((v) => {
117
111
  // strip './' prefix
118
112
  const shortPath = v.path.replace(/^\.\//, "");
@@ -131,9 +125,7 @@ function buildBun(config) {
131
125
  const buildOutput = yield* Effect.tryPromise({
132
126
  try: () => Bun.build(config),
133
127
  catch: (err) => {
134
- const cause = err instanceof AggregateError
135
- ? err.errors?.[0] ?? err
136
- : err;
128
+ const cause = err instanceof AggregateError ? (err.errors?.[0] ?? err) : err;
137
129
  return new Bundle.BundleError({
138
130
  message: "Failed to Bun.build: " + cause,
139
131
  cause: cause,
@@ -0,0 +1,3 @@
1
+ import * as Layer from "effect/Layer";
2
+ import * as ChildProcess from "../ChildProcess.ts";
3
+ export declare const layer: Layer.Layer<ChildProcess.ChildProcessSpawner>;