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
@@ -1,8 +1,6 @@
1
1
  import * as Context from "effect/Context"
2
2
  import * as Fiber from "effect/Fiber"
3
- import * as Layer from "effect/Layer"
4
3
  import * as Option from "effect/Option"
5
- import type { HyperHooks } from "../x/datastar/index.ts"
6
4
  import type { JSX } from "./jsx.d.ts"
7
5
 
8
6
  type Elements = JSX.IntrinsicElements
@@ -11,20 +9,7 @@ type Children = JSX.Children
11
9
 
12
10
  export type { Children, Elements, JSX }
13
11
 
14
- export class Hyper extends Context.Tag("Hyper")<
15
- Hyper,
16
- {
17
- hooks: typeof HyperHooks | undefined
18
- }
19
- >() {}
20
-
21
- export function layer(opts: { hooks: typeof HyperHooks }) {
22
- return Layer.sync(Hyper, () => {
23
- return {
24
- hooks: opts.hooks,
25
- }
26
- })
27
- }
12
+ export class Hyper extends Context.Tag("Hyper")<Hyper, {}>() {}
28
13
 
29
14
  const NoChildren: ReadonlyArray<never> = Object.freeze([])
30
15
 
@@ -41,14 +41,14 @@ const EMPTY_TAGS = [
41
41
  "wbr",
42
42
  ]
43
43
 
44
- // escape an attribute
45
44
  let esc = (str: any) => String(str).replace(/[&<>"']/g, (s) => `&${map[s]};`)
45
+ let escSQ = (str: any) => String(str).replace(/[&<>']/g, (s) => `&${map[s]};`)
46
46
  let map = {
47
47
  "&": "amp",
48
48
  "<": "lt",
49
49
  ">": "gt",
50
50
  '"': "quot",
51
- "'": "apos",
51
+ "'": "#39",
52
52
  }
53
53
 
54
54
  const RAW_TEXT_TAGS = ["script", "style"]
@@ -124,8 +124,10 @@ export function renderToString(
124
124
  const resolvedKey = key === "className" ? "class" : key
125
125
  const value = props[key]
126
126
 
127
- if (key.startsWith("data-") && typeof value === "object") {
128
- result += ` ${esc(resolvedKey)}="${esc(JSON.stringify(value))}"`
127
+ if (key.startsWith("data-") && typeof value === "function") {
128
+ result += ` ${esc(resolvedKey)}="${esc(value.toString())}"`
129
+ } else if (key.startsWith("data-") && typeof value === "object") {
130
+ result += ` ${esc(resolvedKey)}='${escSQ(JSON.stringify(value))}'`
129
131
  } else {
130
132
  result += ` ${esc(resolvedKey)}="${esc(value)}"`
131
133
  }
@@ -2,6 +2,7 @@ import * as Effect from "effect/Effect"
2
2
  import * as Entity from "../Entity.ts"
3
3
  import * as Route from "../Route.ts"
4
4
  import type * as RouteBody from "../RouteBody.ts"
5
+ import type * as Values from "../Values.ts"
5
6
  import * as HyperHtml from "./HyperHtml.ts"
6
7
  import type { JSX } from "./jsx.d.ts"
7
8
 
@@ -20,7 +21,7 @@ function renderValue(
20
21
 
21
22
  function normalizeToEffect<B, A, E, R>(
22
23
  handler: RouteBody.HandlerInput<B, A, E, R>,
23
- context: B,
24
+ context: Values.Simplify<B>,
24
25
  next: (context?: Partial<B> & Record<string, unknown>) => Entity.Entity<A>,
25
26
  ): Effect.Effect<A | Entity.Entity<A>, E, R> {
26
27
  if (Effect.isEffect(handler)) {
@@ -0,0 +1,47 @@
1
+ const HtmlStringSymbol = Symbol.for("HtmlString")
2
+
3
+ export interface HtmlString {
4
+ readonly [HtmlStringSymbol]: true
5
+ readonly value: string
6
+ }
7
+
8
+ const makeHtmlString = (value: string): HtmlString => ({
9
+ [HtmlStringSymbol]: true,
10
+ value,
11
+ })
12
+
13
+ const isHtmlString = (value: unknown): value is HtmlString =>
14
+ typeof value === "object" && value !== null && HtmlStringSymbol in value
15
+
16
+ export type HtmlValue =
17
+ | string
18
+ | number
19
+ | bigint
20
+ | boolean
21
+ | null
22
+ | undefined
23
+ | HtmlString
24
+ | Function
25
+ | Record<string, unknown>
26
+ | ReadonlyArray<HtmlValue>
27
+
28
+ const resolveValue = (value: HtmlValue): string => {
29
+ if (value === null || value === undefined || value === false || value === true) return ""
30
+ if (isHtmlString(value)) return value.value
31
+ if (Array.isArray(value)) return (value as Array<HtmlValue>).map(resolveValue).join("")
32
+ if (typeof value === "function") return value.toString()
33
+ if (typeof value === "object") return JSON.stringify(value)
34
+ if (typeof value === "string") return value
35
+ return String(value)
36
+ }
37
+
38
+ export const html = (strings: TemplateStringsArray, ...values: Array<HtmlValue>): HtmlString => {
39
+ let result = strings[0]
40
+ for (let i = 0; i < values.length; i++) {
41
+ result += resolveValue(values[i])
42
+ result += strings[i + 1]
43
+ }
44
+ return makeHtmlString(result)
45
+ }
46
+
47
+ html.raw = (value: string): HtmlString => makeHtmlString(value)
@@ -1,4 +1,6 @@
1
1
  export * as Hyper from "./Hyper.ts"
2
+ export { html } from "./html.ts"
3
+ export type { HtmlString, HtmlValue } from "./html.ts"
2
4
  export * as HyperHtml from "./HyperHtml.ts"
3
5
  export * as HyperNode from "./HyperNode.ts"
4
6
  export * as HyperRoute from "./HyperRoute.ts"
@@ -1,5 +1,5 @@
1
- import type * as HyperNode from "./hyper/HyperNode.ts"
2
- import type { DatastarAttributes } from "./x/datastar/jsx-datastar.ts"
1
+ import type * as HyperNode from "./HyperNode.ts"
2
+ import type { DatastarAttributes } from "../datastar/jsx.d.ts"
3
3
 
4
4
  /**
5
5
  * Based on JSX types for Surplus, Inferno, and dom-expressions.
@@ -3499,7 +3499,9 @@ export namespace JSX {
3499
3499
  * @url https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
3500
3500
  * @url https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement
3501
3501
  */
3502
- script: ScriptHTMLAttributes<HTMLScriptElement>
3502
+ script:
3503
+ | ScriptHTMLAttributes<HTMLScriptElement>
3504
+ | ScriptHTMLAttributesWithHandler<HTMLScriptElement>
3503
3505
  /**
3504
3506
  * @url https://developer.mozilla.org/en-US/docs/Web/HTML/Element/search
3505
3507
  * @url https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
package/src/index.ts CHANGED
@@ -4,4 +4,5 @@ export * as Entity from "./Entity.ts"
4
4
  export * as FileRouter from "./FileRouter.ts"
5
5
  export * as Route from "./Route.ts"
6
6
  export * as Start from "./Start.ts"
7
+ export * as System from "./System.ts"
7
8
  export * as Unique from "./Unique.ts"
@@ -71,6 +71,117 @@ export default {
71
71
  },
72
72
  },
73
73
 
74
+ "test-space-around": {
75
+ meta: {
76
+ type: "layout",
77
+ docs: {
78
+ description: "Enforce blank lines around test calls (test.describe, test.it, etc.)",
79
+ },
80
+ fixable: "whitespace",
81
+ schema: [],
82
+ messages: {
83
+ requireBlankBefore: "Test call should be preceded by a blank line",
84
+ requireBlankAfter: "Test call should be followed by a blank line",
85
+ },
86
+ },
87
+ create(context) {
88
+ const filename = context.filename || context.getFilename()
89
+ if (!filename.endsWith(".test.ts") && !filename.endsWith(".test.tsx")) {
90
+ return {}
91
+ }
92
+
93
+ function isTestCall(node) {
94
+ return (
95
+ node &&
96
+ node.type === "ExpressionStatement" &&
97
+ node.expression.type === "CallExpression" &&
98
+ node.expression.callee.type === "MemberExpression" &&
99
+ node.expression.callee.object.type === "Identifier" &&
100
+ node.expression.callee.object.name === "test"
101
+ )
102
+ }
103
+
104
+ function checkBlankLines(siblings) {
105
+ const sourceCode = context.sourceCode || context.getSourceCode()
106
+
107
+ for (let i = 0; i < siblings.length; i++) {
108
+ const node = siblings[i]
109
+ if (!isTestCall(node)) continue
110
+
111
+ const prev = siblings[i - 1]
112
+ const next = siblings[i + 1]
113
+
114
+ if (prev) {
115
+ if (node.loc.start.line - prev.loc.end.line < 2) {
116
+ context.report({
117
+ node,
118
+ messageId: "requireBlankBefore",
119
+ fix(fixer) {
120
+ return fixer.insertTextAfter(sourceCode.getLastToken(prev), "\n")
121
+ },
122
+ })
123
+ }
124
+ }
125
+
126
+ if (next) {
127
+ if (next.loc.start.line - node.loc.end.line < 2) {
128
+ context.report({
129
+ node,
130
+ messageId: "requireBlankAfter",
131
+ fix(fixer) {
132
+ return fixer.insertTextAfter(sourceCode.getLastToken(node), "\n")
133
+ },
134
+ })
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ return {
141
+ Program(node) {
142
+ checkBlankLines(node.body)
143
+ },
144
+ BlockStatement(node) {
145
+ checkBlankLines(node.body)
146
+ },
147
+ }
148
+ },
149
+ },
150
+
151
+ // this doens't work reliably and may cause runtime errors
152
+ "export-default-before-functions": {
153
+ meta: {
154
+ type: "suggestion",
155
+ docs: {
156
+ description: "Enforce export default appears before any function declarations",
157
+ },
158
+ schema: [],
159
+ messages: {
160
+ defaultAfterFunction: "export default should appear before function declarations",
161
+ },
162
+ },
163
+ create(context) {
164
+ return {
165
+ Program(node) {
166
+ let seenFunction = false
167
+
168
+ for (const stmt of node.body) {
169
+ if (!seenFunction && isFunction(stmt)) {
170
+ seenFunction = true
171
+ }
172
+
173
+ if (seenFunction && stmt.type === "ExportDefaultDeclaration") {
174
+ context.report({
175
+ node: stmt,
176
+ messageId: "defaultAfterFunction",
177
+ })
178
+ }
179
+ }
180
+ },
181
+ }
182
+ },
183
+ },
184
+
74
185
  "test-assertion-newline": {
75
186
  meta: {
76
187
  type: "layout",
@@ -274,3 +385,21 @@ function getBaseName(source) {
274
385
  function isCapitalized(name) {
275
386
  return name.length > 0 && name[0] >= "A" && name[0] <= "Z"
276
387
  }
388
+
389
+ function isFunction(stmt) {
390
+ const decl = stmt.type === "ExportNamedDeclaration" && stmt.declaration ? stmt.declaration : stmt
391
+
392
+ if (decl.type === "FunctionDeclaration") return true
393
+
394
+ if (
395
+ decl.type === "VariableDeclaration" &&
396
+ decl.declarations.length > 0 &&
397
+ decl.declarations[0].init &&
398
+ (decl.declarations[0].init.type === "ArrowFunctionExpression" ||
399
+ decl.declarations[0].init.type === "FunctionExpression")
400
+ ) {
401
+ return true
402
+ }
403
+
404
+ return false
405
+ }
@@ -0,0 +1,147 @@
1
+ import * as Effect from "effect/Effect"
2
+ import * as Exit from "effect/Exit"
3
+ import * as FiberRef from "effect/FiberRef"
4
+ import * as GlobalValue from "effect/GlobalValue"
5
+ import * as Layer from "effect/Layer"
6
+ import * as Option from "effect/Option"
7
+ import * as Sql from "../../Sql.ts"
8
+
9
+ const errorCode = (error: unknown): string => {
10
+ const e = error as any
11
+ if (typeof e?.errno === "string") return e.errno
12
+ return e?.code ?? "UNKNOWN"
13
+ }
14
+
15
+ const wrapError = (error: unknown): Sql.SqlError =>
16
+ new Sql.SqlError({
17
+ code: errorCode(error),
18
+ message: error instanceof Error ? error.message : String(error),
19
+ cause: error,
20
+ })
21
+
22
+ const wrap = <T>(fn: () => PromiseLike<T>): Effect.Effect<T, Sql.SqlError> =>
23
+ Effect.tryPromise({ try: () => Promise.resolve(fn()), catch: wrapError })
24
+
25
+ const makeValues: Sql.SqlQuery["values"] = (obj: any, ...columns: Array<string>) => {
26
+ const items = Array.isArray(obj) ? obj : [obj]
27
+ const cols = columns.length > 0 ? columns : Object.keys(items[0])
28
+ return { value: items, columns: cols }
29
+ }
30
+
31
+ interface TxState {
32
+ readonly conn: any
33
+ readonly depth: number
34
+ }
35
+
36
+ const currentTransaction = GlobalValue.globalValue(
37
+ Symbol.for("effect-start/sql/bun/currentTransaction"),
38
+ () => FiberRef.unsafeMake<Option.Option<TxState>>(Option.none()),
39
+ )
40
+
41
+ const makeRun =
42
+ (bunSql: any) =>
43
+ <T>(fn: (conn: any) => PromiseLike<T>): Effect.Effect<T, Sql.SqlError> =>
44
+ Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) =>
45
+ wrap(() => fn(Option.isSome(txOpt) ? txOpt.value.conn : bunSql)),
46
+ )
47
+
48
+ const makeWithTransaction =
49
+ (bunSql: any) =>
50
+ <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, Sql.SqlError | E, R> =>
51
+ Effect.uninterruptibleMask((restore) =>
52
+ Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
53
+ if (Option.isSome(txOpt)) {
54
+ const { conn, depth } = txOpt.value
55
+ const name = `sp_${depth}`
56
+ return Effect.gen(function* () {
57
+ yield* wrap(() => conn.unsafe(`SAVEPOINT ${name}`))
58
+ const exit = yield* Effect.exit(
59
+ restore(
60
+ Effect.locally(self, currentTransaction, Option.some({ conn, depth: depth + 1 })),
61
+ ),
62
+ )
63
+ if (Exit.isSuccess(exit)) {
64
+ yield* wrap(() => conn.unsafe(`RELEASE SAVEPOINT ${name}`))
65
+ return exit.value
66
+ }
67
+ yield* wrap(() => conn.unsafe(`ROLLBACK TO SAVEPOINT ${name}`)).pipe(Effect.orDie)
68
+ return yield* exit
69
+ })
70
+ }
71
+
72
+ const runTx = (conn: any) =>
73
+ Effect.gen(function* () {
74
+ yield* wrap(() => conn.unsafe("BEGIN"))
75
+ const exit = yield* Effect.exit(
76
+ restore(Effect.locally(self, currentTransaction, Option.some({ conn, depth: 1 }))),
77
+ )
78
+ if (Exit.isSuccess(exit)) {
79
+ yield* wrap(() => conn.unsafe("COMMIT"))
80
+ return exit.value
81
+ }
82
+ yield* wrap(() => conn.unsafe("ROLLBACK")).pipe(Effect.orDie)
83
+ return yield* exit
84
+ })
85
+
86
+ return Effect.matchEffect(
87
+ wrap(() => bunSql.reserve()),
88
+ {
89
+ onFailure: () => runTx(bunSql),
90
+ onSuccess: (reserved: any) =>
91
+ Effect.ensuring(
92
+ runTx(reserved),
93
+ Effect.sync(() => reserved.release()),
94
+ ),
95
+ },
96
+ )
97
+ }),
98
+ )
99
+
100
+ export const layer = (
101
+ config: ConstructorParameters<typeof Bun.SQL>[0],
102
+ ): Layer.Layer<Sql.SqlClient, Sql.SqlError> =>
103
+ Layer.scoped(
104
+ Sql.SqlClient,
105
+ Effect.acquireRelease(
106
+ Effect.try({
107
+ try: () => {
108
+ const bunSql = new Bun.SQL(config as any)
109
+ const run = makeRun(bunSql)
110
+ const use: Sql.SqlClient["use"] = (fn) =>
111
+ Effect.tryPromise({ try: () => Promise.resolve(fn(bunSql)), catch: wrapError })
112
+ return Object.assign(
113
+ <T = any>(strings: TemplateStringsArray, ...values: Array<unknown>) =>
114
+ run<ReadonlyArray<T>>((conn) => conn(strings, ...values)),
115
+ {
116
+ unsafe: <T = any>(query: string, values?: Array<unknown>) =>
117
+ run<ReadonlyArray<T>>((conn) => conn.unsafe(query, values)),
118
+ values: makeValues,
119
+ withTransaction: makeWithTransaction(bunSql),
120
+ reserve: Effect.acquireRelease(
121
+ wrap(() => bunSql.reserve()),
122
+ (reserved: any) => Effect.sync(() => reserved.release()),
123
+ ).pipe(
124
+ Effect.map(
125
+ (reserved: any): Sql.SqlQuery =>
126
+ Object.assign(
127
+ <T = any>(strings: TemplateStringsArray, ...values: Array<unknown>) =>
128
+ wrap<ReadonlyArray<T>>(() => reserved(strings, ...values)),
129
+ {
130
+ unsafe: <T = any>(query: string, values?: Array<unknown>) =>
131
+ wrap<ReadonlyArray<T>>(() => reserved.unsafe(query, values)),
132
+ values: makeValues,
133
+ },
134
+ ),
135
+ ),
136
+ ),
137
+ close: (options?: { readonly timeout?: number }) =>
138
+ use((bunSql) => bunSql.close(options)),
139
+ use,
140
+ },
141
+ ) satisfies Sql.SqlClient
142
+ },
143
+ catch: wrapError,
144
+ }),
145
+ (client) => client.close().pipe(Effect.orDie),
146
+ ),
147
+ )
@@ -0,0 +1,117 @@
1
+ import * as Effect from "effect/Effect"
2
+ import * as Stream from "effect/Stream"
3
+
4
+ import type * as ChildProcess from "../../ChildProcess.ts"
5
+ import type * as PlatformError from "../../PlatformError.ts"
6
+ import type * as Mssql from "mssql"
7
+ import * as System from "../../System.ts"
8
+ import * as BunChildProcessSpawner from "../../bun/BunChildProcessSpawner.ts"
9
+
10
+ const PORT = 1433
11
+ const PASSWORD = "TestPass123"
12
+ const CONTAINER = "effect-start-mssql"
13
+
14
+ const exec = (
15
+ ...args: Array<string>
16
+ ): Effect.Effect<number, PlatformError.PlatformError, ChildProcess.ChildProcessSpawner> =>
17
+ Effect.scoped(
18
+ Effect.gen(function* () {
19
+ const handle = yield* System.spawn("docker", args, {
20
+ stdout: "ignore",
21
+ stderr: "inherit",
22
+ })
23
+ return yield* handle.exitCode
24
+ }),
25
+ )
26
+
27
+ const execStdout = (
28
+ ...args: Array<string>
29
+ ): Effect.Effect<string, PlatformError.PlatformError, ChildProcess.ChildProcessSpawner> =>
30
+ Effect.scoped(
31
+ Effect.gen(function* () {
32
+ const handle = yield* System.spawn("docker", args, {
33
+ stdout: "pipe",
34
+ stderr: "inherit",
35
+ })
36
+ const [stdout] = yield* Effect.all(
37
+ [handle.stdout.pipe(Stream.decodeText("utf-8"), Stream.mkString), handle.exitCode],
38
+ { concurrency: 2 },
39
+ )
40
+ return stdout
41
+ }),
42
+ )
43
+
44
+ const containerRunning = execStdout("ps", "-q", "-f", `name=${CONTAINER}`).pipe(
45
+ Effect.map((stdout) => stdout.trim().length > 0),
46
+ )
47
+
48
+ const removeContainer = exec("rm", "-f", CONTAINER).pipe(Effect.ignore)
49
+
50
+ type MssqlModule = {
51
+ ConnectionPool: new (config: Mssql.config) => Mssql.ConnectionPool
52
+ }
53
+
54
+ const loadMssql = () => import("mssql") as Promise<MssqlModule>
55
+
56
+ const canConnect = Effect.tryPromise({
57
+ try: async () => {
58
+ const { ConnectionPool } = await loadMssql()
59
+ const pool = new ConnectionPool({
60
+ server: "localhost",
61
+ user: "sa",
62
+ password: PASSWORD,
63
+ port: PORT,
64
+ options: { encrypt: true, trustServerCertificate: true, connectTimeout: 3000 },
65
+ })
66
+ await pool.connect()
67
+ await pool.close()
68
+ return true
69
+ },
70
+ catch: () => false as const,
71
+ }).pipe(Effect.orElseSucceed(() => false))
72
+
73
+ const waitReady = Effect.gen(function* () {
74
+ const deadline = Date.now() + 60_000
75
+ while (Date.now() < deadline) {
76
+ if (yield* canConnect) return
77
+ yield* Effect.sleep("2 seconds")
78
+ }
79
+ return yield* Effect.fail(new Error("Timed out waiting for MSSQL"))
80
+ })
81
+
82
+ const program = Effect.gen(function* () {
83
+ if (yield* containerRunning) {
84
+ yield* Effect.log("MSSQL container already running")
85
+ return
86
+ }
87
+
88
+ yield* removeContainer
89
+
90
+ yield* Effect.log("Starting MSSQL container...")
91
+ const code = yield* exec(
92
+ "run",
93
+ "-d",
94
+ "--name",
95
+ CONTAINER,
96
+ "-p",
97
+ `${PORT}:1433`,
98
+ "-e",
99
+ "ACCEPT_EULA=Y",
100
+ "-e",
101
+ `MSSQL_SA_PASSWORD=${PASSWORD}`,
102
+ "mcr.microsoft.com/azure-sql-edge",
103
+ )
104
+ if (code !== 0) {
105
+ return yield* Effect.fail(new Error(`docker run exited with code ${code}`))
106
+ }
107
+
108
+ yield* waitReady
109
+ yield* Effect.log("MSSQL ready")
110
+ })
111
+
112
+ const run = (effect: Effect.Effect<void, unknown, ChildProcess.ChildProcessSpawner>) =>
113
+ Effect.runPromise(Effect.provide(effect, BunChildProcessSpawner.layer))
114
+
115
+ export const start = () => run(program)
116
+
117
+ export const stop = () => run(removeContainer)