Integrating Astro with Effect: Scopes, Layers, and ManagedRuntime

hello, i'm trying to understand scopes, layers, and ManagedRuntime in order to bridge the gap between Astro and Effect. imagine i have an Auth service with a Live implementation using the Better Auth library
export class Auth extends Context.Tag('astro-auth-prototype/lib/Auth')<
  Auth,
  {
    currentUser(headers: Headers): Effect.Effect<Option.Option<User>, Error>
  }
>() {
  static Live = Layer.succeed(Auth, {
    currentUser: (headers) =>
      Effect.tryPromise(async () => {
        const session = await auth.api.getSession({ headers })
        return Option.fromNullable(session?.user)
      }).pipe(Effect.catchAll(() => Effect.succeed(Option.none()))),
  })
}

it would be really nice to be able to yield* CurrentUser or yield* CurrentRequest in an Effect and have it scoped to the current Astro.request (or whatever is in the Astro global that's only accessible in a .astro file). this seems to be working
export class CurrentRequest extends Context.Tag(
  'astro-auth-prototype/lib/AstroRuntime/CurrentRequest'
)<CurrentRequest, Request>() {
  static layerAstro = (Astro: AstroGlobal) => Layer.succeed(this, Astro.request)
}

export class CurrentUser extends Context.Tag(
  'astro-auth-prototype/lib/AstroRuntime/CurrentUser'
)<CurrentUser, Option.Option<User>>() {
  static layerAstro = (Astro: AstroGlobal) =>
    Layer.effect(
      this,
      Effect.gen(function* () {
        const auth = yield* Auth
        return yield* auth.currentUser(Astro.request.headers)
      })
    )
}

export const defineAstroRuntime = (Astro: AstroGlobal) =>
  ManagedRuntime.make(
    Layer.mergeAll(
      CurrentRequest.layerAstro(Astro),
      CurrentUser.layerAstro(Astro).pipe(Layer.provide(Auth.Live))
    )
  )

which could then by used in a .astro page file:
const requestHandler = Effect.gen(function* () {
  yield* Effect.log('Hello from Effect')
  return yield* CurrentUser
})

const user = await defineAstroRuntime(Astro).runPromise(requestHandler)

is this the best way to pass the Astro global into the Effect system? interested to read the scope and layer docs again but would appreciate any pointers - thank you!
Was this page helpful?