@effect/platform 0.87.12 → 0.88.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.
package/src/HttpApp.ts CHANGED
@@ -5,13 +5,14 @@ import * as Context from "effect/Context"
5
5
  import * as Effect from "effect/Effect"
6
6
  import * as Exit from "effect/Exit"
7
7
  import * as Fiber from "effect/Fiber"
8
- import * as FiberRef from "effect/FiberRef"
8
+ import type * as FiberRef from "effect/FiberRef"
9
9
  import * as GlobalValue from "effect/GlobalValue"
10
10
  import * as Layer from "effect/Layer"
11
11
  import * as Option from "effect/Option"
12
12
  import * as Runtime from "effect/Runtime"
13
13
  import * as Scope from "effect/Scope"
14
14
  import * as Stream from "effect/Stream"
15
+ import type * as Types from "effect/Types"
15
16
  import { unify } from "effect/Unify"
16
17
  import * as HttpBody from "./HttpBody.js"
17
18
  import type { HttpMiddleware } from "./HttpMiddleware.js"
@@ -204,7 +205,8 @@ export const withPreResponseHandler = internal.withPreResponseHandler
204
205
  * @category conversions
205
206
  */
206
207
  export const toWebHandlerRuntime = <R>(runtime: Runtime.Runtime<R>) => {
207
- const run = Runtime.runFork(runtime)
208
+ const httpRuntime: Types.Mutable<Runtime.Runtime<R>> = Runtime.make(runtime)
209
+ const run = Runtime.runFork(httpRuntime)
208
210
  return <E>(self: Default<E, R | Scope.Scope>, middleware?: HttpMiddleware | undefined) => {
209
211
  const resolveSymbol = Symbol.for("@effect/platform/HttpApp/resolve")
210
212
  const httpApp = toHandled(self, (request, response) => {
@@ -225,7 +227,8 @@ export const toWebHandlerRuntime = <R>(runtime: Runtime.Runtime<R>) => {
225
227
  const httpServerRequest = ServerRequest.fromWeb(request)
226
228
  contextMap.set(ServerRequest.HttpServerRequest.key, httpServerRequest)
227
229
  ;(httpServerRequest as any)[resolveSymbol] = resolve
228
- const fiber = run(Effect.locally(httpApp as any, FiberRef.currentContext, Context.unsafeMake(contextMap)))
230
+ httpRuntime.context = Context.unsafeMake(contextMap)
231
+ const fiber = run(httpApp as any)
229
232
  request.signal?.addEventListener("abort", () => {
230
233
  fiber.unsafeInterruptAsFork(ServerError.clientAbortFiberId)
231
234
  }, { once: true })
@@ -248,19 +251,66 @@ export const toWebHandler: <E>(
248
251
  * @since 1.0.0
249
252
  * @category conversions
250
253
  */
251
- export const toWebHandlerLayer = <E, R, RE>(
252
- self: Default<E, R | Scope.Scope>,
254
+ export const toWebHandlerLayerWith = <E, R, RE, EX>(
253
255
  layer: Layer.Layer<R, RE>,
254
- middleware?: HttpMiddleware | undefined
256
+ options: {
257
+ readonly toHandler: (
258
+ runtime: Runtime.Runtime<R>
259
+ ) => Effect.Effect<
260
+ Effect.Effect<ServerResponse.HttpServerResponse, E, R | Scope.Scope | ServerRequest.HttpServerRequest>,
261
+ EX
262
+ >
263
+ readonly middleware?: HttpMiddleware | undefined
264
+ readonly memoMap?: Layer.MemoMap | undefined
265
+ }
255
266
  ): {
256
- readonly close: () => Promise<void>
267
+ readonly dispose: () => Promise<void>
257
268
  readonly handler: (request: Request, context?: Context.Context<never> | undefined) => Promise<Response>
258
269
  } => {
259
270
  const scope = Effect.runSync(Scope.make())
260
- const close = () => Effect.runPromise(Scope.close(scope, Exit.void))
261
- const build = Effect.map(Layer.toRuntime(layer), (_) => toWebHandlerRuntime(_)(self, middleware))
262
- const runner = Effect.runPromise(Scope.extend(build, scope))
263
- const handler = (request: Request, context?: Context.Context<never> | undefined): Promise<Response> =>
264
- runner.then((handler) => handler(request, context))
265
- return { close, handler } as const
271
+ const dispose = () => Effect.runPromise(Scope.close(scope, Exit.void))
272
+
273
+ let handlerCache: ((request: Request, context?: Context.Context<never> | undefined) => Promise<Response>) | undefined
274
+ let handlerPromise:
275
+ | Promise<(request: Request, context?: Context.Context<never> | undefined) => Promise<Response>>
276
+ | undefined
277
+ function handler(request: Request, context?: Context.Context<never> | undefined): Promise<Response> {
278
+ if (handlerCache) {
279
+ return handlerCache(request, context)
280
+ }
281
+ handlerPromise ??= Effect.gen(function*() {
282
+ const runtime = yield* (options.memoMap
283
+ ? Layer.toRuntimeWithMemoMap(layer, options.memoMap)
284
+ : Layer.toRuntime(layer))
285
+ return handlerCache = toWebHandlerRuntime(runtime)(
286
+ yield* options.toHandler(runtime),
287
+ options.middleware
288
+ )
289
+ }).pipe(
290
+ Scope.extend(scope),
291
+ Effect.runPromise
292
+ )
293
+ return handlerPromise.then((f) => f(request, context))
294
+ }
295
+ return { dispose, handler } as const
266
296
  }
297
+
298
+ /**
299
+ * @since 1.0.0
300
+ * @category conversions
301
+ */
302
+ export const toWebHandlerLayer = <E, R, RE>(
303
+ self: Default<E, R | Scope.Scope>,
304
+ layer: Layer.Layer<R, RE>,
305
+ options?: {
306
+ readonly memoMap?: Layer.MemoMap | undefined
307
+ readonly middleware?: HttpMiddleware | undefined
308
+ }
309
+ ): {
310
+ readonly dispose: () => Promise<void>
311
+ readonly handler: (request: Request, context?: Context.Context<never> | undefined) => Promise<Response>
312
+ } =>
313
+ toWebHandlerLayerWith(layer, {
314
+ ...options,
315
+ toHandler: () => Effect.succeed(self)
316
+ })
@@ -9,7 +9,6 @@ import * as Effect from "effect/Effect"
9
9
  import * as FiberRef from "effect/FiberRef"
10
10
  import { compose, constant, dual, identity } from "effect/Function"
11
11
  import * as Layer from "effect/Layer"
12
- import * as ManagedRuntime from "effect/ManagedRuntime"
13
12
  import * as Option from "effect/Option"
14
13
  import * as Scope from "effect/Scope"
15
14
  import * as Tracer from "effect/Tracer"
@@ -1165,29 +1164,15 @@ export const toWebHandler = <
1165
1164
  if (options?.disableLogger !== true) {
1166
1165
  middleware = middleware ? compose(middleware, HttpMiddleware.logger) : HttpMiddleware.logger
1167
1166
  }
1168
- const RouterLayer = options?.routerConfig
1169
- ? Layer.provide(layer, Layer.succeed(RouterConfig, options.routerConfig))
1170
- : layer
1171
- const runtime = ManagedRuntime.make(
1172
- Layer.provideMerge(appLayer, RouterLayer) as any,
1173
- options?.memoMap
1174
- )
1175
- let handlerCached:
1176
- | ((request: globalThis.Request, context?: Context.Context<never> | undefined) => Promise<Response>)
1177
- | undefined
1178
- const handlerPromise = Effect.gen(function*() {
1179
- const router = yield* HttpRouter
1180
- const effect = router.asHttpEffect()
1181
- const rt = yield* runtime.runtimeEffect
1182
- const handler = HttpApp.toWebHandlerRuntime(rt)(effect, middleware)
1183
- handlerCached = handler
1184
- return handler
1185
- }).pipe(runtime.runPromise)
1186
- function handler(request: globalThis.Request, context?: Context.Context<never> | undefined): Promise<Response> {
1187
- if (handlerCached !== undefined) {
1188
- return handlerCached(request, context)
1189
- }
1190
- return handlerPromise.then((handler) => handler(request, context))
1191
- }
1192
- return { handler, dispose: runtime.dispose } as const
1167
+ const RouterLayer: Layer.Layer<HttpRouter | A, E> = Layer.provideMerge(
1168
+ appLayer,
1169
+ options?.routerConfig
1170
+ ? Layer.provide(layer, Layer.succeed(RouterConfig, options.routerConfig))
1171
+ : layer
1172
+ ) as any
1173
+ return HttpApp.toWebHandlerLayerWith(RouterLayer, {
1174
+ toHandler: (r) => Effect.succeed(Context.get(r.context, HttpRouter).asHttpEffect()),
1175
+ middleware,
1176
+ memoMap: options?.memoMap
1177
+ })
1193
1178
  }