1import { WS_METHODS } from "@t3tools/contracts";
2import * as Stream from "effect/Stream";
3import { Atom } from "effect/reactivity";
4
5import type { EnvironmentRegistry } from "../connection/registry.ts";
6import {
7 createAtomCommandScheduler,
8 createEnvironmentRpcCommand,
9 createEnvironmentRpcQueryAtomFamily,
10 createEnvironmentRpcSubscriptionAtomFamily,
11} from "./runtime.ts";
12
13export function createPreviewEnvironmentAtoms<R, E>(
14 runtime: Atom.AtomRuntime<EnvironmentRegistry | R, E>,
15) {
16 const lifecycleScheduler = createAtomCommandScheduler();
17 const statusScheduler = createAtomCommandScheduler();
18 const lifecycleConcurrency = {
19 mode: "serial" as const,
20 key: ({ environmentId, input }: { environmentId: string; input: { threadId: string } }) =>
21 JSON.stringify([environmentId, input.threadId]),
22 };
23 return {
24 list: createEnvironmentRpcQueryAtomFamily(runtime, {
25 label: "environment-data:preview:list",
26 tag: WS_METHODS.previewList,
27 staleTimeMs: 5_000,
28 }),
29 events: createEnvironmentRpcSubscriptionAtomFamily(runtime, {
30 label: "environment-data:preview:events",
31 tag: WS_METHODS.subscribePreviewEvents,
32 // Stream atoms publish only the last value per chunk; every preview event must arrive.
33 transform: (stream) => stream.pipe(Stream.rechunk(1)),
34 }),
35 discoveredServers: createEnvironmentRpcSubscriptionAtomFamily(runtime, {
36 label: "environment-data:preview:discovered-servers",
37 tag: WS_METHODS.subscribeDiscoveredLocalServers,
38 // Configured URLs are part of this atom's key. Dispose immediately so
39 // unmounted projects stop contributing probe candidates on the server.
40 idleTtlMs: 0,
41 }),
42 open: createEnvironmentRpcCommand(runtime, {
43 label: "environment-data:preview:open",
44 tag: WS_METHODS.previewOpen,
45 scheduler: lifecycleScheduler,
46 concurrency: lifecycleConcurrency,
47 }),
48 resize: createEnvironmentRpcCommand(runtime, {
49 label: "environment-data:preview:resize",
50 tag: WS_METHODS.previewResize,
51 scheduler: lifecycleScheduler,
52 concurrency: lifecycleConcurrency,
53 }),
54 adjust: createEnvironmentRpcCommand(runtime, {
55 label: "environment-data:preview:adjust",
56 tag: WS_METHODS.previewAdjust,
57 scheduler: lifecycleScheduler,
58 concurrency: lifecycleConcurrency,
59 }),
60 close: createEnvironmentRpcCommand(runtime, {
61 label: "environment-data:preview:close",
62 tag: WS_METHODS.previewClose,
63 scheduler: lifecycleScheduler,
64 concurrency: lifecycleConcurrency,
65 }),
66 clearProfile: createEnvironmentRpcCommand(runtime, {
67 label: "environment-data:preview:clear-profile",
68 tag: WS_METHODS.previewClearProfile,
69 }),
70 reportProfiles: createEnvironmentRpcCommand(runtime, {
71 label: "environment-data:preview:report-profiles",
72 tag: WS_METHODS.previewReportProfiles,
73 concurrency: { mode: "latest", key: ({ environmentId }) => environmentId },
74 }),
75 stopLocalServer: createEnvironmentRpcCommand(runtime, {
76 label: "environment-data:preview:stop-local-server",
77 tag: WS_METHODS.previewStopLocalServer,
78 }),
79 reportStatus: createEnvironmentRpcCommand(runtime, {
80 label: "environment-data:preview:report-status",
81 tag: WS_METHODS.previewReportStatus,
82 scheduler: statusScheduler,
83 concurrency: {
84 mode: "latest",
85 key: ({ environmentId, input }) =>
86 JSON.stringify([environmentId, input.threadId, input.tabId]),
87 },
88 }),
89 };
90}