import { EnvironmentId, type OrchestrationShellSnapshot } from "@t3tools/contracts";import * as Arr from "effect/Array";import { pipe } from "effect/Function";import * as Option from "effect/Option";import * as Order from "effect/Order";import { AsyncResult, Atom } from "effect/unstable/reactivity"; export interface ArchivedSnapshotEntry { readonly environmentId: EnvironmentId; readonly snapshot: OrchestrationShellSnapshot;} export interface ArchivedThreadSnapshotsState { readonly snapshots: ReadonlyArray<ArchivedSnapshotEntry>; readonly error: string | null; readonly isLoading: boolean;} const ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR = "\u001f";const environmentIdOrder = Order.String as Order.Order<EnvironmentId>; export function makeArchivedThreadsEnvironmentKey( environmentIds: ReadonlyArray<EnvironmentId>,): string { return pipe(environmentIds, Arr.sort(environmentIdOrder), (sortedEnvironmentIds) => sortedEnvironmentIds.join(ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR), );} export function parseArchivedThreadsEnvironmentKey(key: string): ReadonlyArray<EnvironmentId> { if (key.length === 0) { return []; } return pipe( key.split(ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR), Arr.map((environmentId) => EnvironmentId.make(environmentId)), );} export function createArchivedThreadSnapshotsAtomFamily<E>(options: { readonly getSnapshotAtom: ( environmentId: EnvironmentId, ) => Atom.Atom<AsyncResult.AsyncResult<OrchestrationShellSnapshot, E>>; readonly labelPrefix: string;}) { return Atom.family((environmentKey: string) => Atom.make((get): ArchivedThreadSnapshotsState => { const snapshots: ArchivedSnapshotEntry[] = []; let error: string | null = null; let isLoading = false; for (const environmentId of parseArchivedThreadsEnvironmentKey(environmentKey)) { const result = get(options.getSnapshotAtom(environmentId)); isLoading ||= result.waiting; const snapshot = Option.getOrNull(AsyncResult.value(result)); if (snapshot !== null) { snapshots.push({ environmentId, snapshot }); } if (error === null && result._tag === "Failure") { error = "Failed to load archived threads."; } } return { snapshots, error, isLoading }; }).pipe(Atom.withLabel(`${options.labelPrefix}:${environmentKey}`)), );}
import { EnvironmentId, type OrchestrationShellSnapshot } from "@t3tools/contracts";
import * as Arr from "effect/Array";
import { pipe } from "effect/Function";
import * as Option from "effect/Option";
import * as Order from "effect/Order";
import { AsyncResult, Atom } from "effect/unstable/reactivity";
export interface ArchivedSnapshotEntry {
readonly environmentId: EnvironmentId;
readonly snapshot: OrchestrationShellSnapshot;
}
export interface ArchivedThreadSnapshotsState {
readonly snapshots: ReadonlyArray<ArchivedSnapshotEntry>;
readonly error: string | null;
readonly isLoading: boolean;
}
const ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR = "\u001f";
const environmentIdOrder = Order.String as Order.Order<EnvironmentId>;
export function makeArchivedThreadsEnvironmentKey(
environmentIds: ReadonlyArray<EnvironmentId>,
): string {
return pipe(environmentIds, Arr.sort(environmentIdOrder), (sortedEnvironmentIds) =>
sortedEnvironmentIds.join(ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR),
);
}
export function parseArchivedThreadsEnvironmentKey(key: string): ReadonlyArray<EnvironmentId> {
if (key.length === 0) {
return [];
}
return pipe(
key.split(ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR),
Arr.map((environmentId) => EnvironmentId.make(environmentId)),
);
}
export function createArchivedThreadSnapshotsAtomFamily<E>(options: {
readonly getSnapshotAtom: (
environmentId: EnvironmentId,
) => Atom.Atom<AsyncResult.AsyncResult<OrchestrationShellSnapshot, E>>;
readonly labelPrefix: string;
}) {
return Atom.family((environmentKey: string) =>
Atom.make((get): ArchivedThreadSnapshotsState => {
const snapshots: ArchivedSnapshotEntry[] = [];
let error: string | null = null;
let isLoading = false;
for (const environmentId of parseArchivedThreadsEnvironmentKey(environmentKey)) {
const result = get(options.getSnapshotAtom(environmentId));
isLoading ||= result.waiting;
const snapshot = Option.getOrNull(AsyncResult.value(result));
if (snapshot !== null) {
snapshots.push({ environmentId, snapshot });
}
if (error === null && result._tag === "Failure") {
error = "Failed to load archived threads.";
}
}
return { snapshots, error, isLoading };
}).pipe(Atom.withLabel(`${options.labelPrefix}:${environmentKey}`)),
);
}