/** * The server entry's public surface. Client-only APIs — hooks and signals — must * NOT be exported here: a Server Component resolves `@tmonier/effract` through the * `react-server` condition to this entry, so their *absence* is exactly what makes * `hook(...)` / `observe(...)` a compile error in a Server Component instead of a * runtime surprise. This test guards that surface so the enforcement can't * silently regress (a `next build` proves it end-to-end; this proves it in unit). */ import { describe, expect, it } from 'vitest'; import * as server from './index.server.ts'; describe('server entry surface (react-server condition)', () => { it('exports the authoring + server-render API', () => { expect(typeof server.rec).toBe('function'); expect(typeof server.mount).toBe('function'); expect(typeof server.driveServerRec).toBe('function'); }); it('exports the query cache service + the mutation constructor (ADR 0008)', () => { // Both are React-free, so a universal service that constructs a `mutation` // (or invalidates through `QueryCache`) resolves in the server graph too. expect(typeof server.mutation).toBe('function'); expect(typeof server.QueryCache).toBe('function'); // a Context service key (class) }); it('does NOT export a VERSION constant — dropped from the surface (ADR 0008)', () => { expect('VERSION' in server).toBe(false); }); it('exports the server-safe reactive state primitives', () => { // `atom`/`derive`/`defer` are pure Effect-backed state — no React — so a // *universal* service that holds reactive state resolves under the // `react-server` condition too (a deferred read is a plain read on the // server). Only the hooks that *read* an atom in a component are absent. expect(typeof server.atom).toBe('function'); expect(typeof server.derive).toBe('function'); expect(typeof server.defer).toBe('function'); }); it('does NOT export client-only APIs — they cannot exist in a Server Component', () => { for (const name of ['hook', 'observe', 'Observe', 'useAtom', 'useAtomValue', 'Runtime']) { expect(name in server, `${name} must not be exported from the server entry`).toBe(false); } }); it('does NOT export hydration plumbing — state transfer is automatic', () => { // `renderToStream` (the `/ssr` subpath) embeds state; the client `mount` // seeds it. `dehydrate`/`hydrate` are internal to that pair. for (const name of ['dehydrate', 'hydrate', 'HydrationBoundary']) { expect(name in server, `${name} must not be exported from the server entry`).toBe(false); } }); });