1import { describe, expect, it } from "@effect/vitest";
2import {
3 AuthOrchestrationOperateScope,
4 EnvironmentId,
5 ExecutionEnvironmentDescriptor,
6 type ServerConfig,
7} from "@t3tools/contracts";
8import * as Effect from "effect/Effect";
9import * as Fiber from "effect/Fiber";
10import * as Layer from "effect/Layer";
11import * as Schema from "effect/Schema";
12import * as SubscriptionRef from "effect/SubscriptionRef";
13import { Atom, AtomRegistry } from "effect/reactivity";
14
15import { HubConnection, type HubConnectionState } from "../connection/hub.ts";
16import { createHubConnectionAtoms, createHubEnvironmentCapabilitiesAtom } from "./hub.ts";
17
18const hubId = EnvironmentId.make("hub");
19const id = EnvironmentId.make("offline");
20const descriptor = Schema.decodeUnknownSync(ExecutionEnvironmentDescriptor)({
21 environmentId: id,
22 label: "Offline machine",
23 platform: { os: "darwin", arch: "arm64" },
24 serverVersion: "test",
25 capabilities: {},
26});
27const initial = {
28 connection: { environmentId: hubId, label: "Hub", httpBaseUrl: "https://hub.example/" },
29 directory: {
30 hubEnvironmentId: hubId,
31 environments: [
32 {
33 environmentId: id,
34 label: "Offline machine",
35 httpBaseUrl: "https://hub.example/environments/offline/",
36 scopes: [AuthOrchestrationOperateScope],
37 descriptor,
38 },
39 ],
40 },
41 inbox: {
42 environments: [
43 {
44 environmentId: id,
45 pendingThreadIds: [],
46 snapshot: {
47 schemaVersion: 1,
48 snapshotSequence: 0,
49 projects: [],
50 threads: [],
51 archivedThreads: [],
52 },
53 },
54 ],
55 },
56 refreshing: false,
57 error: null,
58} satisfies HubConnectionState;
59
60describe("central organization availability", () => {
61 it.effect(
62 "permits offline organization from the directory grant without a source configuration",
63 () =>
64 Effect.gen(function* () {
65 const state = yield* SubscriptionRef.make<HubConnectionState>(initial);
66 const runtime = Atom.runtime(
67 Layer.succeed(HubConnection, {
68 state,
69 connect: () => Effect.void,
70 connectAuthenticated: () => Effect.void,
71 headers: Effect.succeed({}),
72 refresh: Effect.void,
73 refreshInbox: Effect.void,
74 disconnect: Effect.void,
75 organize: () => Effect.succeedNone,
76 }),
77 );
78 const hub = createHubConnectionAtoms(runtime);
79 const configs = Atom.make<ReadonlyMap<EnvironmentId, ServerConfig>>(new Map());
80 const capabilities = createHubEnvironmentCapabilitiesAtom(configs, hub);
81 const registry = AtomRegistry.make();
82 yield* Effect.addFinalizer(() => Effect.sync(() => registry.dispose()));
83 registry.mount(hub.organizationPermissionAtom(id));
84 yield* AtomRegistry.getResult(registry, hub.stateAtom);
85
86 expect(registry.get(hub.organizationPermissionAtom(id))).toBe(true);
87 expect(registry.get(hub.organizationPermissionAtom(EnvironmentId.make("other")))).toBe(
88 false,
89 );
90 expect(registry.get(configs).size).toBe(0);
91 expect(registry.get(capabilities).get(id)).toMatchObject({
92 threadSettlement: true,
93 threadSnooze: true,
94 threadPinning: true,
95 threadPinReorder: true,
96 threadActiveReorder: true,
97 threadAutoSettleOptOut: true,
98 });
99
100 expect(registry.get(capabilities).get(id)?.threadTitleRegeneration).not.toBe(true);
101 const revoked = yield* Effect.forkChild(
102 Effect.callback<void>((resume) => {
103 const unsubscribe = registry.subscribe(
104 hub.organizationPermissionAtom(id),
105 () => {
106 if (!registry.get(hub.organizationPermissionAtom(id))) resume(Effect.void);
107 },
108 { immediate: true },
109 );
110 return Effect.sync(unsubscribe);
111 }),
112 );
113 yield* SubscriptionRef.set(state, {
114 ...initial,
115 directory: {
116 ...initial.directory,
117 environments: initial.directory.environments.map((entry) => ({ ...entry, scopes: [] })),
118 },
119 });
120 yield* Fiber.join(revoked);
121 expect(registry.get(hub.organizationPermissionAtom(id))).toBe(false);
122 expect(registry.get(capabilities).get(id)?.threadSettlement).not.toBe(true);
123 }).pipe(Effect.scoped),
124 );
125});