effect-start 0.19.0 → 0.20.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 (144) hide show
  1. package/README.md +3 -3
  2. package/dist/Development.d.ts +3 -3
  3. package/dist/Development.js +3 -2
  4. package/dist/Effectify.d.ts +212 -0
  5. package/dist/Effectify.js +19 -0
  6. package/dist/FilePathPattern.d.ts +29 -0
  7. package/dist/FilePathPattern.js +86 -0
  8. package/dist/FileRouter.d.ts +39 -41
  9. package/dist/FileRouter.js +104 -158
  10. package/dist/FileRouterCodegen.d.ts +7 -8
  11. package/dist/FileRouterCodegen.js +97 -66
  12. package/dist/PlatformError.d.ts +46 -0
  13. package/dist/PlatformError.js +43 -0
  14. package/dist/PlatformRuntime.d.ts +23 -0
  15. package/dist/PlatformRuntime.js +42 -0
  16. package/dist/RouteBody.d.ts +1 -1
  17. package/dist/Start.d.ts +34 -3
  18. package/dist/Start.js +31 -6
  19. package/dist/bun/BunPlatformHttpServer.d.ts +10 -0
  20. package/dist/bun/BunPlatformHttpServer.js +53 -0
  21. package/dist/bun/BunRoute.d.ts +3 -5
  22. package/dist/bun/BunRoute.js +9 -17
  23. package/dist/bun/BunRuntime.d.ts +2 -1
  24. package/dist/bun/BunRuntime.js +10 -5
  25. package/dist/bun/BunServer.d.ts +33 -0
  26. package/dist/bun/BunServer.js +133 -0
  27. package/dist/bun/BunServerRequest.d.ts +60 -0
  28. package/dist/bun/BunServerRequest.js +252 -0
  29. package/dist/bun/index.d.ts +1 -1
  30. package/dist/bun/index.js +1 -1
  31. package/dist/datastar/actions/fetch.d.ts +30 -0
  32. package/dist/datastar/actions/fetch.js +411 -0
  33. package/dist/datastar/actions/peek.d.ts +1 -0
  34. package/dist/datastar/actions/peek.js +14 -0
  35. package/dist/datastar/actions/setAll.d.ts +1 -0
  36. package/dist/datastar/actions/setAll.js +13 -0
  37. package/dist/datastar/actions/toggleAll.d.ts +1 -0
  38. package/dist/datastar/actions/toggleAll.js +13 -0
  39. package/dist/datastar/attributes/attr.d.ts +1 -0
  40. package/dist/datastar/attributes/attr.js +49 -0
  41. package/dist/datastar/attributes/bind.d.ts +1 -0
  42. package/dist/datastar/attributes/bind.js +183 -0
  43. package/dist/datastar/attributes/class.d.ts +1 -0
  44. package/dist/datastar/attributes/class.js +50 -0
  45. package/dist/datastar/attributes/computed.d.ts +1 -0
  46. package/dist/datastar/attributes/computed.js +27 -0
  47. package/dist/datastar/attributes/effect.d.ts +1 -0
  48. package/dist/datastar/attributes/effect.js +10 -0
  49. package/dist/datastar/attributes/indicator.d.ts +1 -0
  50. package/dist/datastar/attributes/indicator.js +32 -0
  51. package/dist/datastar/attributes/init.d.ts +1 -0
  52. package/dist/datastar/attributes/init.js +27 -0
  53. package/dist/datastar/attributes/jsonSignals.d.ts +1 -0
  54. package/dist/datastar/attributes/jsonSignals.js +31 -0
  55. package/dist/datastar/attributes/on.d.ts +1 -0
  56. package/dist/datastar/attributes/on.js +59 -0
  57. package/dist/datastar/attributes/onIntersect.d.ts +1 -0
  58. package/dist/datastar/attributes/onIntersect.js +54 -0
  59. package/dist/datastar/attributes/onInterval.d.ts +1 -0
  60. package/dist/datastar/attributes/onInterval.js +31 -0
  61. package/dist/datastar/attributes/onSignalPatch.d.ts +1 -0
  62. package/dist/datastar/attributes/onSignalPatch.js +44 -0
  63. package/dist/datastar/attributes/ref.d.ts +1 -0
  64. package/dist/datastar/attributes/ref.js +11 -0
  65. package/dist/datastar/attributes/show.d.ts +1 -0
  66. package/dist/datastar/attributes/show.js +32 -0
  67. package/dist/datastar/attributes/signals.d.ts +1 -0
  68. package/dist/datastar/attributes/signals.js +18 -0
  69. package/dist/datastar/attributes/style.d.ts +1 -0
  70. package/dist/datastar/attributes/style.js +56 -0
  71. package/dist/datastar/attributes/text.d.ts +1 -0
  72. package/dist/datastar/attributes/text.js +27 -0
  73. package/dist/datastar/engine.d.ts +156 -0
  74. package/dist/datastar/engine.js +971 -0
  75. package/dist/datastar/index.d.ts +24 -0
  76. package/dist/datastar/index.js +24 -0
  77. package/dist/datastar/load.d.ts +24 -0
  78. package/dist/datastar/load.js +24 -0
  79. package/dist/datastar/utils.d.ts +51 -0
  80. package/dist/datastar/utils.js +205 -0
  81. package/dist/datastar/watchers/patchElements.d.ts +1 -0
  82. package/dist/datastar/watchers/patchElements.js +420 -0
  83. package/dist/datastar/watchers/patchSignals.d.ts +1 -0
  84. package/dist/datastar/watchers/patchSignals.js +15 -0
  85. package/dist/index.d.ts +1 -1
  86. package/dist/index.js +1 -1
  87. package/dist/node/NodeFileSystem.d.ts +7 -0
  88. package/dist/node/NodeFileSystem.js +420 -0
  89. package/dist/node/NodeUtils.d.ts +2 -0
  90. package/dist/node/NodeUtils.js +20 -0
  91. package/dist/x/tailwind/plugin.js +1 -1
  92. package/package.json +11 -7
  93. package/src/Development.ts +26 -25
  94. package/src/{node/Effectify.ts → Effectify.ts} +10 -3
  95. package/src/FilePathPattern.ts +115 -0
  96. package/src/FileRouter.ts +178 -255
  97. package/src/FileRouterCodegen.ts +135 -92
  98. package/src/{node/PlatformError.ts → PlatformError.ts} +34 -19
  99. package/src/PlatformRuntime.ts +97 -0
  100. package/src/RouteBody.ts +1 -1
  101. package/src/RouteHttp.ts +3 -1
  102. package/src/Start.ts +62 -14
  103. package/src/bun/BunPlatformHttpServer.ts +88 -0
  104. package/src/bun/BunRoute.ts +12 -22
  105. package/src/bun/BunRuntime.ts +21 -5
  106. package/src/bun/BunServer.ts +228 -0
  107. package/src/bun/index.ts +1 -1
  108. package/src/datastar/README.md +18 -0
  109. package/src/datastar/actions/fetch.ts +609 -0
  110. package/src/datastar/actions/peek.ts +17 -0
  111. package/src/datastar/actions/setAll.ts +20 -0
  112. package/src/datastar/actions/toggleAll.ts +20 -0
  113. package/src/datastar/attributes/attr.ts +50 -0
  114. package/src/datastar/attributes/bind.ts +220 -0
  115. package/src/datastar/attributes/class.ts +57 -0
  116. package/src/datastar/attributes/computed.ts +33 -0
  117. package/src/datastar/attributes/effect.ts +11 -0
  118. package/src/datastar/attributes/indicator.ts +39 -0
  119. package/src/datastar/attributes/init.ts +35 -0
  120. package/src/datastar/attributes/jsonSignals.ts +38 -0
  121. package/src/datastar/attributes/on.ts +71 -0
  122. package/src/datastar/attributes/onIntersect.ts +65 -0
  123. package/src/datastar/attributes/onInterval.ts +39 -0
  124. package/src/datastar/attributes/onSignalPatch.ts +63 -0
  125. package/src/datastar/attributes/ref.ts +12 -0
  126. package/src/datastar/attributes/show.ts +33 -0
  127. package/src/datastar/attributes/signals.ts +22 -0
  128. package/src/datastar/attributes/style.ts +63 -0
  129. package/src/datastar/attributes/text.ts +30 -0
  130. package/src/datastar/engine.ts +1341 -0
  131. package/src/datastar/index.ts +25 -0
  132. package/src/datastar/utils.ts +286 -0
  133. package/src/datastar/watchers/patchElements.ts +554 -0
  134. package/src/datastar/watchers/patchSignals.ts +15 -0
  135. package/src/index.ts +1 -1
  136. package/src/node/{FileSystem.ts → NodeFileSystem.ts} +2 -2
  137. package/src/node/{Utils.ts → NodeUtils.ts} +2 -0
  138. package/src/x/tailwind/plugin.ts +1 -1
  139. package/src/FileRouterCodegen.todo.ts +0 -1133
  140. package/src/FileRouterPattern.ts +0 -59
  141. package/src/RouterPattern.ts +0 -416
  142. package/src/StartApp.ts +0 -47
  143. package/src/bun/BunHttpServer.ts +0 -303
  144. /package/src/bun/{BunHttpServer_web.ts → BunServerRequest.ts} +0 -0
@@ -0,0 +1,88 @@
1
+ import * as HttpApp from "@effect/platform/HttpApp"
2
+ import * as HttpServer from "@effect/platform/HttpServer"
3
+ import * as HttpServerError from "@effect/platform/HttpServerError"
4
+ import * as HttpServerRequest from "@effect/platform/HttpServerRequest"
5
+ import type * as Bun from "bun"
6
+ import * as Effect from "effect/Effect"
7
+ import * as FiberSet from "effect/FiberSet"
8
+ import type * as Scope from "effect/Scope"
9
+ import * as BunServer from "./BunServer.ts"
10
+ import * as BunServerRequest from "./BunServerRequest.ts"
11
+
12
+ /**
13
+ * From times when we used @effect/platform
14
+ * Not used any more internally. Kept for the future,
15
+ * in case someone will need it for whatever reason. [2026]
16
+ */
17
+ export const make: Effect.Effect<
18
+ HttpServer.HttpServer,
19
+ never,
20
+ Scope.Scope | BunServer.BunServer
21
+ > = Effect.gen(function*() {
22
+ const bunServer = yield* BunServer.BunServer
23
+
24
+ return HttpServer.make({
25
+ address: {
26
+ _tag: "TcpAddress",
27
+ port: bunServer.server.port!,
28
+ hostname: bunServer.server.hostname!,
29
+ },
30
+ serve(httpApp, middleware) {
31
+ return Effect.gen(function*() {
32
+ const runFork = yield* FiberSet.makeRuntime<never>()
33
+ const runtime = yield* Effect.runtime<never>()
34
+ const app = HttpApp.toHandled(
35
+ httpApp,
36
+ (request, response) =>
37
+ Effect.sync(() => {
38
+ ;(request as BunServerRequest.ServerRequestImpl).resolve(
39
+ BunServerRequest.makeResponse(request, response, runtime),
40
+ )
41
+ }),
42
+ middleware,
43
+ )
44
+
45
+ function handler(
46
+ request: Request,
47
+ server: Bun.Server<BunServerRequest.WebSocketContext>,
48
+ ) {
49
+ return new Promise<Response>((resolve, _reject) => {
50
+ const fiber = runFork(Effect.provideService(
51
+ app,
52
+ HttpServerRequest.HttpServerRequest,
53
+ new BunServerRequest.ServerRequestImpl(
54
+ request,
55
+ resolve,
56
+ removeHost(request.url),
57
+ server,
58
+ ),
59
+ ))
60
+ request.signal.addEventListener("abort", () => {
61
+ runFork(
62
+ fiber.interruptAsFork(HttpServerError.clientAbortFiberId),
63
+ )
64
+ }, { once: true })
65
+ })
66
+ }
67
+
68
+ yield* Effect.acquireRelease(
69
+ Effect.sync(() => {
70
+ bunServer.pushHandler(handler)
71
+ }),
72
+ () =>
73
+ Effect.sync(() => {
74
+ bunServer.popHandler()
75
+ }),
76
+ )
77
+ })
78
+ },
79
+ })
80
+ })
81
+
82
+ const removeHost = (url: string) => {
83
+ if (url[0] === "/") {
84
+ return url
85
+ }
86
+ const index = url.indexOf("/", url.indexOf("//") + 2)
87
+ return index === -1 ? "/" : url.slice(index)
88
+ }
@@ -4,12 +4,12 @@ import * as Data from "effect/Data"
4
4
  import * as Effect from "effect/Effect"
5
5
  import * as Option from "effect/Option"
6
6
  import * as Entity from "../Entity.ts"
7
+ import * as FilePathPattern from "../FilePathPattern.ts"
7
8
  import * as Hyper from "../hyper/Hyper.ts"
8
9
  import * as HyperHtml from "../hyper/HyperHtml.ts"
9
- import * as Unique from "../Unique.ts"
10
10
  import * as Route from "../Route.ts"
11
- import * as RouterPattern from "../RouterPattern.ts"
12
- import * as BunHttpServer from "./BunHttpServer.ts"
11
+ import * as Unique from "../Unique.ts"
12
+ import * as BunServer from "./BunServer.ts"
13
13
 
14
14
  const INTERNAL_FETCH_HEADER = "x-effect-start-internal-fetch"
15
15
 
@@ -60,7 +60,7 @@ export function htmlBundle(
60
60
  { request: Request },
61
61
  string,
62
62
  BunRouteError,
63
- BunHttpServer.BunHttpServer
63
+ BunServer.BunServer
64
64
  >,
65
65
  ]
66
66
  > {
@@ -68,7 +68,7 @@ export function htmlBundle(
68
68
  BunDescriptors & { format: "html" } & { request: Request },
69
69
  string,
70
70
  BunRouteError,
71
- BunHttpServer.BunHttpServer
71
+ BunServer.BunServer
72
72
  > = (context, next) =>
73
73
  Effect.gen(function*() {
74
74
  const originalRequest = context.request
@@ -87,7 +87,7 @@ export function htmlBundle(
87
87
  )
88
88
  }
89
89
 
90
- const bunServer = yield* BunHttpServer.BunHttpServer
90
+ const bunServer = yield* BunServer.BunServer
91
91
  const url = new URL(originalRequest.url)
92
92
 
93
93
  const internalPath = `${bunPrefix}${url.pathname}`
@@ -152,7 +152,7 @@ export function htmlBundle(
152
152
  { request: Request },
153
153
  string,
154
154
  BunRouteError,
155
- BunHttpServer.BunHttpServer
155
+ BunServer.BunServer
156
156
  >(handler, descriptors)
157
157
 
158
158
  return Route.set(
@@ -181,9 +181,7 @@ export type BunRoutes = Record<string, BunServerRouteHandler>
181
181
  * - /exact - Exact match
182
182
  * - /users/:id - Full-segment named param
183
183
  * - /path/* - Directory wildcard
184
- * - /* - Catch-all
185
- * - /[[id]] - Optional param (implemented via `/` and `/:id`)
186
- * - /[[...rest]] - Optional rest param (implemented via `/` and `/*`)
184
+ * - /[[404]] - Catch-all / Rest
187
185
  *
188
186
  * Unsupported patterns (cannot be implemented in Bun):
189
187
  * - /pk_[id] - Prefix before param
@@ -196,24 +194,16 @@ export type BunRoutes = Record<string, BunServerRouteHandler>
196
194
  export function validateBunPattern(
197
195
  pattern: string,
198
196
  ): Option.Option<BunRouteError> {
199
- const segments = RouterPattern.parse(pattern)
200
-
201
- const unsupported = Array.findFirst(segments, (seg) => {
202
- if (seg._tag === "ParamSegment") {
203
- return seg.prefix !== undefined || seg.suffix !== undefined
204
- }
197
+ const segs = FilePathPattern.segments(pattern)
205
198
 
206
- return false
207
- })
199
+ const invalid = Array.findFirst(segs, (seg) => seg._tag === "InvalidSegment")
208
200
 
209
- if (Option.isSome(unsupported)) {
201
+ if (Option.isSome(invalid)) {
210
202
  return Option.some(
211
203
  new BunRouteError({
212
204
  reason: "UnsupportedPattern",
213
205
  pattern,
214
- message:
215
- `Pattern "${pattern}" uses prefixed/suffixed params (prefix_[param] or [param]_suffix) `
216
- + `which cannot be implemented in Bun.serve.`,
206
+ message: `Pattern "${pattern}" contains invalid segment.`,
217
207
  }),
218
208
  )
219
209
  }
@@ -1,11 +1,24 @@
1
- import { makeRunMain } from "@effect/platform/Runtime"
2
- import { constVoid } from "effect/Function"
1
+ import type * as Fiber from "effect/Fiber"
2
+ import * as GlobalValue from "effect/GlobalValue"
3
+ import * as MutableRef from "effect/MutableRef"
4
+ import * as PlatformRuntime from "../PlatformRuntime.ts"
3
5
 
4
- export const runMain = makeRunMain(({
6
+ const mainFiber = GlobalValue.globalValue(
7
+ Symbol.for("effect-start/BunRuntime/existingFiber"),
8
+ () =>
9
+ MutableRef.make<Fiber.RuntimeFiber<unknown, unknown> | undefined>(
10
+ undefined,
11
+ ),
12
+ )
13
+
14
+ export const runMain = PlatformRuntime.makeRunMain(({
5
15
  fiber,
6
16
  teardown,
7
17
  }) => {
8
- const keepAlive = setInterval(constVoid, 2 ** 31 - 1)
18
+ const prevFiber = MutableRef.get(mainFiber)
19
+
20
+ MutableRef.set(mainFiber, fiber)
21
+
9
22
  let receivedSignal = false
10
23
 
11
24
  fiber.addObserver((exit) => {
@@ -13,7 +26,6 @@ export const runMain = makeRunMain(({
13
26
  process.removeListener("SIGINT", onSigint)
14
27
  process.removeListener("SIGTERM", onSigint)
15
28
  }
16
- clearInterval(keepAlive)
17
29
  teardown(exit, (code) => {
18
30
  if (receivedSignal || code !== 0) {
19
31
  process.exit(code)
@@ -30,4 +42,8 @@ export const runMain = makeRunMain(({
30
42
 
31
43
  process.on("SIGINT", onSigint)
32
44
  process.on("SIGTERM", onSigint)
45
+
46
+ if (prevFiber) {
47
+ prevFiber.unsafeInterruptAsFork(prevFiber.id())
48
+ }
33
49
  })
@@ -0,0 +1,228 @@
1
+ import * as Socket from "@effect/platform/Socket"
2
+ import * as Bun from "bun"
3
+ import * as Config from "effect/Config"
4
+ import * as Context from "effect/Context"
5
+ import * as Deferred from "effect/Deferred"
6
+ import * as Effect from "effect/Effect"
7
+ import * as Exit from "effect/Exit"
8
+ import * as Layer from "effect/Layer"
9
+ import * as Option from "effect/Option"
10
+ import * as Runtime from "effect/Runtime"
11
+ import type * as Scope from "effect/Scope"
12
+ import * as PathPattern from "../PathPattern.ts"
13
+ import * as PlataformRuntime from "../PlatformRuntime.ts"
14
+ import * as Route from "../Route.ts"
15
+ import * as RouteHttp from "../RouteHttp.ts"
16
+ import * as RouteMount from "../RouteMount.ts"
17
+ import * as RouteTree from "../RouteTree.ts"
18
+ import * as BunRoute from "./BunRoute.ts"
19
+ import * as BunServerRequest from "./BunServerRequest.ts"
20
+
21
+ type FetchHandler = (
22
+ request: Request,
23
+ server: Bun.Server<BunServerRequest.WebSocketContext>,
24
+ ) => Response | Promise<Response>
25
+
26
+ /**
27
+ * Basically `Omit<Bun.Serve.Options, "fetch" | "error" | "websocket">`
28
+ * TypeScript 5.9 cannot verify discriminated union types used in
29
+ * {@link Bun.serve} so we need to define them explicitly.
30
+ */
31
+ interface BunServeOptions {
32
+ readonly port?: number
33
+ readonly hostname?: string
34
+ readonly reusePort?: boolean
35
+ readonly ipv6Only?: boolean
36
+ readonly idleTimeout?: number
37
+ readonly development?: boolean
38
+ }
39
+
40
+ export type BunServer = {
41
+ readonly server: Bun.Server<BunServerRequest.WebSocketContext>
42
+ readonly pushHandler: (fetch: FetchHandler) => void
43
+ readonly popHandler: () => void
44
+ }
45
+
46
+ export const BunServer = Context.GenericTag<BunServer>(
47
+ "effect-start/BunServer",
48
+ )
49
+
50
+ export const make = (
51
+ options: BunServeOptions,
52
+ ): Effect.Effect<
53
+ BunServer,
54
+ never,
55
+ Scope.Scope
56
+ > =>
57
+ Effect.gen(function*() {
58
+ const routes = yield* Effect.serviceOption(Route.Routes).pipe(
59
+ Effect.andThen(Option.getOrUndefined),
60
+ )
61
+
62
+ const port = yield* Config.number("PORT").pipe(
63
+ Effect.catchTag("ConfigError", () => {
64
+ return PlataformRuntime.isAgentHarness()
65
+ ? Effect.succeed(0) // random port
66
+ : Effect.succeed(3000)
67
+ }),
68
+ )
69
+ const hostname = yield* Config.string("HOSTNAME").pipe(
70
+ Effect.catchTag("ConfigError", () => Effect.succeed(undefined)),
71
+ )
72
+
73
+ const handlerStack: Array<FetchHandler> = [
74
+ function(_request, _server) {
75
+ return new Response("not found", { status: 404 })
76
+ },
77
+ ]
78
+
79
+ const service = BunServer.of({
80
+ // During the construction we need to create a service imlpementation
81
+ // first so we can provide it in the runtime that will be used in web
82
+ // handlers. After we create the runtime, we set it below so it's always
83
+ // available at runtime.
84
+ // An alternative approach would be to use Bun.Server.reload but I prefer
85
+ // to avoid it since it's badly documented and has bunch of bugs.
86
+ server: undefined as any,
87
+ pushHandler(fetch) {
88
+ handlerStack.push(fetch)
89
+ reload()
90
+ },
91
+ popHandler() {
92
+ handlerStack.pop()
93
+ reload()
94
+ },
95
+ })
96
+
97
+ const runtime = yield* Effect.runtime().pipe(
98
+ Effect.andThen(Runtime.provideService(BunServer, service)),
99
+ )
100
+
101
+ let currentRoutes: BunRoute.BunRoutes = routes
102
+ ? yield* walkBunRoutes(runtime, routes)
103
+ : {}
104
+
105
+ const websocket: Bun.WebSocketHandler<BunServerRequest.WebSocketContext> = {
106
+ open(ws) {
107
+ Deferred.unsafeDone(ws.data.deferred, Exit.succeed(ws))
108
+ },
109
+ message(ws, message) {
110
+ ws.data.run(message)
111
+ },
112
+ close(ws, code, closeReason) {
113
+ Deferred.unsafeDone(
114
+ ws.data.closeDeferred,
115
+ Socket.defaultCloseCodeIsError(code)
116
+ ? Exit.fail(
117
+ new Socket.SocketCloseError({
118
+ reason: "Close",
119
+ code,
120
+ closeReason,
121
+ }),
122
+ )
123
+ : Exit.void,
124
+ )
125
+ },
126
+ }
127
+
128
+ const server = Bun.serve({
129
+ port,
130
+ hostname,
131
+ ...options,
132
+ routes: currentRoutes,
133
+ fetch: handlerStack[0],
134
+ websocket,
135
+ })
136
+
137
+ // @ts-expect-error
138
+ service.server = server
139
+
140
+ yield* Effect.addFinalizer(() =>
141
+ Effect.sync(() => {
142
+ server.stop()
143
+ })
144
+ )
145
+
146
+ const reload = () => {
147
+ server.reload({
148
+ fetch: handlerStack[handlerStack.length - 1],
149
+ routes: currentRoutes,
150
+ websocket,
151
+ })
152
+ }
153
+
154
+ const bunServer = BunServer.of({
155
+ server,
156
+ pushHandler(fetch) {
157
+ handlerStack.push(fetch)
158
+ reload()
159
+ },
160
+ popHandler() {
161
+ handlerStack.pop()
162
+ reload()
163
+ },
164
+ })
165
+
166
+ return bunServer
167
+ })
168
+
169
+ /**
170
+ * Provides HttpServer using BunServer under the hood.
171
+ */
172
+ export const layer = (
173
+ options?: BunServeOptions,
174
+ ): Layer.Layer<BunServer> =>
175
+ Layer.scoped(
176
+ BunServer,
177
+ make(options ?? {}),
178
+ )
179
+
180
+ export const withLogAddress = <A, E, R>(
181
+ layer: Layer.Layer<A, E, R>,
182
+ ) =>
183
+ Layer
184
+ .effectDiscard(
185
+ BunServer.pipe(
186
+ Effect.andThen(server =>
187
+ Effect.log(
188
+ `Listening on ${server.server.hostname}:${server.server.port}`,
189
+ )
190
+ ),
191
+ ),
192
+ )
193
+ .pipe(
194
+ Layer.provideMerge(layer),
195
+ )
196
+
197
+ function walkBunRoutes(
198
+ runtime: Runtime.Runtime<BunServer>,
199
+ tree: RouteTree.RouteTree,
200
+ ) {
201
+ return Effect.gen(function*() {
202
+ const bunRoutes: BunRoute.BunRoutes = {}
203
+ const pathGroups = new Map<string, RouteMount.MountedRoute[]>()
204
+ const toWebHandler = RouteHttp.toWebHandlerRuntime(runtime)
205
+
206
+ for (const route of RouteTree.walk(tree)) {
207
+ const bunDescriptors = BunRoute.descriptors(route)
208
+ if (bunDescriptors) {
209
+ const htmlBundle = yield* Effect.promise(bunDescriptors.bunLoad)
210
+ bunRoutes[`${bunDescriptors.bunPrefix}/*`] = htmlBundle
211
+ }
212
+
213
+ const path = Route.descriptor(route).path
214
+ const group = pathGroups.get(path) ?? []
215
+ group.push(route)
216
+ pathGroups.set(path, group)
217
+ }
218
+
219
+ for (const [path, routes] of pathGroups) {
220
+ const handler = toWebHandler(routes)
221
+ for (const bunPath of PathPattern.toBun(path)) {
222
+ bunRoutes[bunPath] = handler
223
+ }
224
+ }
225
+
226
+ return bunRoutes
227
+ })
228
+ }
package/src/bun/index.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export * as BunBundle from "./BunBundle.ts"
2
- export * as BunHttpServer from "./BunHttpServer.ts"
3
2
  export * as BunImportTrackerPlugin from "./BunImportTrackerPlugin.ts"
4
3
  export * as BunRoute from "./BunRoute.ts"
4
+ export * as BunServer from "./BunServer.ts"
@@ -0,0 +1,18 @@
1
+ # Datastar
2
+
3
+ This is a port of [Datastar](https://github.com/starfederation/datastar) of magnificent Star Federation.
4
+
5
+ We experimentally place it inside Effect Start to have tighter integration with it and provide
6
+ great out-of-the-box experience. After cleaning up the code, we're at around ~90kb of source code.
7
+ We can probably cut it down by another ~10kb if we remove DataStar expression and use JS functions directly.
8
+
9
+ Based on `812cbe9` (2025-02-05) following changes were made:
10
+
11
+ - Path aliases converted to relative imports: `@engine/*` → `./engine/*`, etc.
12
+ - Flattened `plugins/` directory: `plugins/actions/` → `actions/`, etc.
13
+ - Deleted the `ALIAS` type declaration: removed `globals.d.ts`,
14
+ no alias conditional in `utils/text.ts` & `applyAttributePlugin` in `engine.ts`.
15
+ - Removed plugin header comments.
16
+ - Updated type declaration to conform to `erasableSyntaxOnly`:
17
+ - Converted `enum ReactiveFlags` and `enum EffectFlags` to `const` objects with `as const`
18
+ - Added type aliases `ReactiveFlags_X` to replace `ReactiveFlags.X` namespace types