refactor(gui): move the snapshot-store engine into the client runtime
The data layer no longer depends on the React glue package, and business plugins no longer depend on web-react at all: - The store engine (zustand vanilla + immer + persist + dev freeze), defineStore, and shallowEqual move to @deepseek-ai/dsh-client-runtime, exported from the ./client main entry — no ./store subpath survives on either package (the web-react one is deleted, none is opened on runtime). - Store products are bare snapshot sources: useSelector leaves SnapshotStore/StoreInstance and Session; every hook is composed at the binding site in web-react's renderer (per-source cached uSES binding). The SlotRendererHost sessions face carries bare observables only. - SessionProvider becomes a standard-kit seat: an entry whose children declare a session-scope slot receives the framework component as a prop, retiring the last value import of web-react from plugin packages. UseSession and the session-area types now live in ui-slots. - web-react shrinks to the shell-only React glue (renderer, providers, uSES bridge); zustand/immer belong to runtime alone; the module-table seed and tsdown externals drop the web-react/store seat. - NODE_ENV replacement is defined once in the shared tsdown client preset (browser bundles inline the engine and lost vite's define); the 3-line process.env typecheck shim moves to runtime with the engine. - Stray tsc artifacts (.js/.d.ts/.d.ts.map beside sources under src/) swept repo-wide; they shadow real sources under vitest resolution. Verified: both aggregate typecheck programs at zero; 604 client tests green; repo-wide grep for web-react/store at zero; real-host playwright run 7/7 including persist round-trip. ci: fix test/docs
This commit is contained in:
@@ -19,7 +19,7 @@ import {
|
||||
type StoredEntry,
|
||||
} from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import {
|
||||
HostContext, SlotAssemblyError, observableHook, useHost, useSessionCell,
|
||||
HostContext, SessionProvider, SlotAssemblyError, observableHook, useHost, useSessionCell,
|
||||
} from './session-provider.tsx'
|
||||
|
||||
type InjectedProps = Record<string, unknown>
|
||||
@@ -120,26 +120,36 @@ class SlotErrorBoundary extends Component<
|
||||
|
||||
/**
|
||||
* Standard-kit synthesis shared by both scope branches: the global
|
||||
* useSessions hook, the store pair when declared, and the renderSlot binding
|
||||
* when children are declared. Every member is identity-stable (hook cache /
|
||||
* host store cache / binding cache), so spreading a fresh kit object per
|
||||
* render never churns child subscriptions.
|
||||
* useSessions hook, the session pair, the store pair when declared, the
|
||||
* renderSlot binding when children are declared, and the SessionProvider
|
||||
* seat when the children declare a session-scope slot. Hosts hand out BARE
|
||||
* observable sources (hooks never cross the host contract); every hook is
|
||||
* bound HERE, cached per source (observableHook), so spreading a fresh kit
|
||||
* object per render never churns child subscriptions.
|
||||
*/
|
||||
function standardKit(host: SlotRendererHost, entry: StoredEntry, cell: SessionCell | undefined): {
|
||||
kit: InjectedProps; actions: object | undefined
|
||||
} {
|
||||
const kit: InjectedProps = { useSessions: observableHook(host.sessions.list) }
|
||||
if (cell !== undefined) {
|
||||
kit['useSession'] = cell.useSession
|
||||
kit['useSession'] = observableHook(cell.session)
|
||||
kit['sessionId'] = cell.sessionId
|
||||
}
|
||||
const store = host.storeOf(entry, cell?.sessionId)
|
||||
if (store !== undefined) {
|
||||
kit['useStore'] = store.useSelector
|
||||
// The instance IS an observable snapshot source (contract getSnapshot/
|
||||
// subscribe); the useStore hook binds here, cached per instance.
|
||||
kit['useStore'] = observableHook(store)
|
||||
kit['actions'] = store.actions
|
||||
}
|
||||
if (entry.children !== undefined) {
|
||||
kit['renderSlot'] = boundRenderSlot(host, entry)
|
||||
// SessionProvider standard seat: entries declaring a session-scope child
|
||||
// render the session area, so the framework hands them the self-wired
|
||||
// provider (module-level component = stable reference; no value import).
|
||||
if (Object.values(entry.children).some((spec) => spec.scope === 'session')) {
|
||||
kit['SessionProvider'] = SessionProvider
|
||||
}
|
||||
}
|
||||
return { kit, actions: store?.actions }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user