diff --git a/packages/core/src/effect/layer-node.ts b/packages/core/src/effect/layer-node.ts index dc7aa972f0..dba328c270 100644 --- a/packages/core/src/effect/layer-node.ts +++ b/packages/core/src/effect/layer-node.ts @@ -74,7 +74,7 @@ type MakeInput< T extends Tag | undefined = undefined, > = NodeIdentity & { readonly layer: Implementation - readonly deps: Items & CheckDependencies> + readonly deps: (Items | (() => Items)) & CheckDependencies> readonly tag?: T } @@ -90,7 +90,9 @@ export function make< name: input.service !== undefined ? input.service.key : input.name, service: input.service, implementation: input.layer, - dependencies: input.deps, + get dependencies() { + return typeof input.deps === "function" ? input.deps() : input.deps + }, tag: input.tag, } } diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index 73fd80e141..c268c78931 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -1033,7 +1033,8 @@ const SHELL_MAX_CAPTURE_BYTES = 1024 * 1024 export const node = makeGlobalNode({ service: Service, layer: layer.pipe(Layer.orDie), - deps: [ + // Defer the execution node across the Session/runner module cycle until the graph is compiled. + deps: () => [ Job.node, Database.node, EventV2.node, diff --git a/packages/core/test/effect/layer-node/layer-node-types.test.ts b/packages/core/test/effect/layer-node/layer-node-types.test.ts index 366bf746da..4deb3e6c71 100644 --- a/packages/core/test/effect/layer-node/layer-node-types.test.ts +++ b/packages/core/test/effect/layer-node/layer-node-types.test.ts @@ -32,6 +32,7 @@ const b = make({ service: B, layer: bLayer, deps: [a] }) const c = make({ service: C, layer: cLayer, deps: [a, b] }) const failing = make({ service: A, layer: failingA, deps: [] }) const dependent = make({ service: B, layer: bLayer, deps: [failing] }) +make({ service: B, layer: bLayer, deps: () => [a] }) const inputA = LayerNode.unbound(A, tags.values.app) const inputDependent = make({ service: B, layer: bLayer, deps: [inputA] }) @@ -46,6 +47,9 @@ make({ service: A, name: "a", layer: aLayer, deps: [] }) // @ts-expect-error B requires A make({ service: B, layer: bLayer, deps: [] }) +// @ts-expect-error Lazy dependencies must still provide A +make({ service: B, layer: bLayer, deps: () => [] }) + // @ts-expect-error C requires A and B make({ service: C, layer: cLayer, deps: [a] }) diff --git a/packages/core/test/effect/layer-node/layer-node.test.ts b/packages/core/test/effect/layer-node/layer-node.test.ts index b671792c59..4fa9fe9877 100644 --- a/packages/core/test/effect/layer-node/layer-node.test.ts +++ b/packages/core/test/effect/layer-node/layer-node.test.ts @@ -37,6 +37,12 @@ describe("layer node", () => { expect(await Effect.runPromise(program)).toBe("hello production") }) + test("resolves lazy dependencies when compiling", async () => { + const greeting = make({ service: Greeting, layer: greetingLayer, deps: () => [value] }) + const program = Effect.map(Greeting, (item) => item.value).pipe(Effect.provide(build(greeting))) + expect(await Effect.runPromise(program)).toBe("hello production") + }) + test("exposes roots but hides transitive dependencies", () => { const layer = build(LayerNode.group([greeting])) const check: Layer.Layer = layer