1import * as Effect from "effect/Effect";
2import * as Layer from "effect/Layer";
3import * as ManagedRuntime from "effect/ManagedRuntime";
4
5import { layerRemoteHttpClient } from "@t3tools/client-runtime/rpc";
6
7import * as Dpop from "../features/cloud/dpop";
8import * as ManagedRelayLayer from "../features/cloud/managedRelayLayer";
9import { resolveCloudPublicConfig } from "../features/cloud/publicConfig";
10import * as Tracing from "../features/observability/tracing";
11import * as NativeWebSocket from "../native/nativeWebSocket";
12import * as Persistence from "../persistence/layer";
13import { disposeOnFoundationReplace, type FoundationHotModule } from "./foundation-fast-refresh";
14import { whenProtectedDataAvailable } from "./protectedData";
15
16declare const module: { readonly hot?: FoundationHotModule } | undefined;
17
18function configuredRelayUrl(): string {
19 return resolveCloudPublicConfig().relay.url ?? "http://relay.invalid";
20}
21
22const layerHttpClient = layerRemoteHttpClient(fetch);
23
24type RuntimeLayerSource =
25 | ReturnType<typeof ManagedRelayLayer.layer>
26 | typeof NativeWebSocket.layer
27 | typeof Dpop.layer
28 | typeof layerHttpClient
29 | typeof Persistence.layer
30 | typeof Tracing.layer;
31
32const layerRuntime = Layer.merge(
33 ManagedRelayLayer.layer(configuredRelayUrl()),
34 NativeWebSocket.layer,
35).pipe(
36 Layer.provideMerge(Dpop.layer),
37 Layer.provideMerge(layerHttpClient),
38 Layer.provideMerge(Tracing.layer.pipe(Layer.provide(layerHttpClient))),
39 Layer.provideMerge(Persistence.layer),
40 // These layers read the keychain and the database while they build, and a
41 // failed build is kept for the life of the process.
42 Layer.provide(Layer.effectDiscard(Effect.promise(whenProtectedDataAvailable))),
43);
44
45export const runtime: ManagedRuntime.ManagedRuntime<
46 Layer.Success<RuntimeLayerSource>,
47 Layer.Error<RuntimeLayerSource>
48> = ManagedRuntime.make(layerRuntime);
49
50export const layer: Layer.Layer<
51 Layer.Success<RuntimeLayerSource>,
52 Layer.Error<RuntimeLayerSource>
53> = Layer.effectContext(runtime.contextEffect);
54
55disposeOnFoundationReplace(typeof module === "undefined" ? undefined : module.hot, () =>
56 runtime.dispose(),
57);