@deepseek-ai/dsh-client-ui-slots 0.0.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,183 @@
1
+ /** React-free contracts between the slot host and an installed renderer. */
2
+ import type { ReactNode } from 'react';
3
+ import type { SlotEntryDef, SlotSpec, StoredEntry, Translate } from './index.ts';
4
+ /**
5
+ * The locale face the render machinery consumes: namespace binding plus an
6
+ * observable revision (getSnapshot/subscribe pair — the same HostObservable
7
+ * currency as every other standard-kit source). The revision moves on every
8
+ * active-locale or registry change; the renderer re-derives each entry's `t`
9
+ * from (namespace, revision), so a locale switch hands out NEW function
10
+ * references and memoized components re-render naturally. Implemented by the
11
+ * locale plugin, installed through the runtime SlotsService (installLocale).
12
+ * Install before the first render that needs the seat: outlets bind their
13
+ * revision subscription at mount, and a face appearing later has no channel
14
+ * to notify already-mounted outlets (the locale plugin is immediately-tier
15
+ * infrastructure, so normal compositions install during boot).
16
+ */
17
+ export interface LocaleFace extends HostObservable<{
18
+ revision: number;
19
+ }> {
20
+ /**
21
+ * Bind a namespace to a translate function reading the active locale at
22
+ * call time. Identity may be stable per namespace — freshness of rendered
23
+ * text is carried by the renderer's (ns, revision) seat derivation, not by
24
+ * this binding.
25
+ * @param ns - dictionary namespace.
26
+ * @returns the namespace-bound translate function.
27
+ */
28
+ bind(ns: string): Translate;
29
+ }
30
+ /** Minimal observable surface for host-provided standard-kit data sources. */
31
+ export interface HostObservable<T> {
32
+ getSnapshot(): T;
33
+ subscribe(fn: () => void): () => void;
34
+ }
35
+ /**
36
+ * Type-erased store instance face at the render boundary (the typed twin is
37
+ * {@link StoreInstance}): a bare snapshot source plus the draft-stripped
38
+ * action callbacks. No React hook crosses this boundary — the render machinery
39
+ * binds `useStore` from the source at its own side (cached per instance);
40
+ * typing lands at the component boundary via {@link PropsStore}.
41
+ */
42
+ export interface StoreInstanceLike {
43
+ getSnapshot(): unknown;
44
+ /**
45
+ * Subscribe to state changes (uSES subscribe side).
46
+ * @param fn - change callback.
47
+ * @returns unsubscribe.
48
+ */
49
+ subscribe(fn: () => void): () => void;
50
+ readonly actions: Record<string, (...params: never[]) => void>;
51
+ }
52
+ /**
53
+ * Per-session standard props resolved per session id (identity-stable per
54
+ * session scope; a recreated scope yields a new info). Plugins contribute
55
+ * members through the runtime `sessions.provide` contract; the render side binds
56
+ * every `hooks` source into a `use<Name>` selector hook (hooks never appear
57
+ * on the host contract) and spreads `props` verbatim. The runtime itself
58
+ * contributes the first entry (`'session'` → `useSession`).
59
+ */
60
+ export interface SessionMaybeProvideInfo {
61
+ /** Current session id, absent while the application is in no-session mode. */
62
+ sessionId: string | undefined;
63
+ /**
64
+ * Static hook roster. Each value is absent with the session; keys remain so
65
+ * session-maybe entries always receive the same hook-shaped standard kit.
66
+ */
67
+ hooks: Record<string, HostObservable<unknown> | undefined>;
68
+ /** Static plain-member roster; values are undefined with the session. */
69
+ props: Record<string, unknown>;
70
+ /**
71
+ * Key-addressed projection value sources (the useProjection framework seat;
72
+ * session-projection subsystem page: docs/subsystems/session-projection.md).
73
+ * Unlike `hooks`, the key space is open — values
74
+ * arrive from host-computed push frames — so the render side binds per
75
+ * resolved key instead of per static roster member. Faces are always
76
+ * defined per key (absence is an `undefined` snapshot); the whole member is
77
+ * absent with the session.
78
+ */
79
+ projections?: {
80
+ faceOf(key: string): HostObservable<unknown>;
81
+ } | undefined;
82
+ }
83
+ /** Definite per-session standard props resolved for strict session slots. */
84
+ export interface SessionProvideInfo extends SessionMaybeProvideInfo {
85
+ sessionId: string;
86
+ /** Bare observable sources, keyed by hook base name ('session' → useSession). */
87
+ hooks: Record<string, HostObservable<unknown>>;
88
+ }
89
+ /** renderSlot dispatch options at the machinery level. */
90
+ export interface RenderOpts {
91
+ entryKey?: string;
92
+ only?: string;
93
+ fallback?: ReactNode;
94
+ /** Opaque occurrence context consumed only by function-valued injected Hooks. */
95
+ hookContext?: unknown;
96
+ }
97
+ /** Host surface the runtime SlotsService presents to the installed renderer. */
98
+ export interface SlotRendererHost {
99
+ /**
100
+ * Subscribe to a key's registration changes (microtask-batched).
101
+ * @param key - slot key.
102
+ * @param fn - change callback.
103
+ * @returns unsubscribe.
104
+ */
105
+ subscribe(key: string, fn: () => void): () => void;
106
+ /**
107
+ * Monotonic version for uSES pairing.
108
+ * @param key - slot key.
109
+ * @returns current version.
110
+ */
111
+ getVersion(key: string): number;
112
+ /**
113
+ * Snapshot the registered entries for a key (stable reference between mutations).
114
+ * @param key - slot key.
115
+ * @returns entries in registration (list: order) sequence.
116
+ */
117
+ entriesOf(key: string): readonly StoredEntry[];
118
+ /**
119
+ * Declared runtime spec from the declarations ledger.
120
+ * @param key - slot key.
121
+ * @returns the spec, or undefined while the key is undeclared (outlets render empty).
122
+ */
123
+ specOf(key: string): SlotSpec<SlotEntryDef> | undefined;
124
+ /**
125
+ * Stale-authorization check: whether the entry is still in the ledger.
126
+ * @param entry - a previously rendered entry.
127
+ * @returns false once the entry's registration was disposed.
128
+ */
129
+ isLive(entry: StoredEntry): boolean;
130
+ /**
131
+ * Resolve (create or return cached) the store instance for an entry's
132
+ * declared handle under a scope key; lifecycle rides the ledger axis.
133
+ * @param entry - entry whose declaration carries the handle.
134
+ * @param scopeKey - session id for session-scope slots, undefined for root scope.
135
+ * @returns the instance, or undefined when the entry declares no store.
136
+ */
137
+ storeOf(entry: StoredEntry, scopeKey: string | undefined): StoreInstanceLike | undefined;
138
+ /** Session-side standard-kit sources. */
139
+ sessions: {
140
+ /** Session list source backing the useSessions standard hook. */
141
+ list: HostObservable<unknown>;
142
+ /**
143
+ * Atomic current-session provide projection used by SessionProvider:
144
+ * selection changes and provider-roster changes publish through this one
145
+ * source, so a stable current id cannot strand mounted entries on an
146
+ * obsolete hook/prop schema. Carries the static roster with sessionId
147
+ * undefined while no current session resolves.
148
+ */
149
+ provideInfo: HostObservable<SessionMaybeProvideInfo>;
150
+ };
151
+ /** Workspace-side standard-kit sources. */
152
+ workspaces: {
153
+ /** Workspace list source backing the useWorkspaces standard hook. */
154
+ list: HostObservable<unknown>;
155
+ };
156
+ /**
157
+ * Installed locale face backing the `t` standard seat (absent until the
158
+ * locale plugin installs one; rendering an entry that declared `locale:`
159
+ * without it is an assembly failure).
160
+ */
161
+ locale?: LocaleFace | undefined;
162
+ }
163
+ /** The installation contract: runtime owns install()/renderSlot(); web-react implements rendering. */
164
+ export interface SlotRenderer {
165
+ /**
166
+ * Render the root slot tree over the host surface (the only ctx-level entry).
167
+ * @param host - the installing service's host surface.
168
+ * @param ownerProps - owner props from the shell's renderSlot('root', ...) call.
169
+ * @returns the rendered tree.
170
+ */
171
+ renderRoot(host: SlotRendererHost, ownerProps: object): ReactNode;
172
+ }
173
+ /** Thrown when a retained renderSlot binding is invoked after its declaring entry was disposed. */
174
+ export declare class StaleAuthorizationError extends Error {
175
+ }
176
+ /**
177
+ * Thrown when a renderSlot binding is invoked for a key outside its entry's
178
+ * children declaration (plain-JS backstop; typed callers are narrowed
179
+ * statically).
180
+ */
181
+ export declare class SlotOwnershipError extends Error {
182
+ }
183
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1,111 @@
1
+ /** Framework-neutral store contracts for slot registrations and the runtime engine. */
2
+ /**
3
+ * Typed selector hook over a snapshot source. Canonical shape for the whole
4
+ * slot system (web-react's engine hook is structurally identical; the
5
+ * framework is the only party that ever constructs one).
6
+ */
7
+ export type SnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?: (a: S, b: S) => boolean) => S;
8
+ /**
9
+ * Selector hook over a source that follows the current session. The hook is
10
+ * always present, while its selected value is absent whenever no session is
11
+ * current. This keeps hook call sites stable across no-session/session
12
+ * transitions without pretending that a session snapshot exists.
13
+ */
14
+ export type MaybeSnapshotSelectorHook<T> = <S>(sel: (s: T) => S, eq?: (a: S, b: S) => boolean) => S | undefined;
15
+ /**
16
+ * Action declaration table: pure immer-draft transforms over the store state,
17
+ * declared as the store's complete write set (the audit face — components can
18
+ * only write through these).
19
+ */
20
+ export type ActionsDecl<T> = Record<string, (draft: T, ...params: any[]) => void>;
21
+ /**
22
+ * Draft-stripped callback form of an actions table: what components
23
+ * (`props.actions`) and inject factories receive — the framework bakes the
24
+ * draft parameter away by binding each action to the resolved instance.
25
+ */
26
+ export type BakedActions<T, A extends ActionsDecl<T>> = {
27
+ [K in keyof A]: A[K] extends (draft: T, ...params: infer P) => void ? (...params: P) => void : never;
28
+ };
29
+ /**
30
+ * Store declaration spec: initial-state factory (a lambda so every instance
31
+ * gets a fresh state), optional persistence key (mechanical, framework-run),
32
+ * and the actions write set.
33
+ */
34
+ export interface StoreSpec<T, A extends ActionsDecl<T>> {
35
+ init: () => T;
36
+ persist?: string;
37
+ actions: A;
38
+ }
39
+ /**
40
+ * Live engine instance: the create() product consumed by the render machinery
41
+ * and by tests. A bare snapshot source plus the baked write set — no React
42
+ * hook rides the engine product (the engine lives in the React-free runtime);
43
+ * the render machinery binds the `useStore` hook from this source on its own
44
+ * side, cached per instance. Production components and render paths never
45
+ * call create() themselves — instance lifecycle is the framework's.
46
+ */
47
+ export interface StoreInstance<T, A extends ActionsDecl<T>> {
48
+ readonly actions: BakedActions<T, A>;
49
+ getSnapshot(): T;
50
+ /**
51
+ * Subscribe to state changes (uSES subscribe side).
52
+ * @param fn - change callback.
53
+ * @returns unsubscribe.
54
+ */
55
+ subscribe(fn: () => void): () => void;
56
+ /**
57
+ * Drop this instance's persisted value (no-op for non-persist specs). The
58
+ * framework calls it when the owning scope dies for good — a pruned session
59
+ * must not leave orphaned storage keys behind.
60
+ */
61
+ clearPersisted(): void;
62
+ }
63
+ /**
64
+ * Store handle: spec + state/actions types + shared identity + instance
65
+ * factory in one value. Handles are constructed in apply world (shared across
66
+ * registrations of one plugin) or by the framework from a registrant's
67
+ * factory (exclusive). Never export a handle at module level — module-cache
68
+ * identity is a disguised singleton across plugin reloads.
69
+ */
70
+ export interface StoreHandle<T, A extends ActionsDecl<T>> {
71
+ readonly spec: StoreSpec<T, A>;
72
+ /**
73
+ * Create a live engine instance (framework machinery and tests only).
74
+ * @param scopeKey - session id for session-scope instances; suffixes the
75
+ * persist key so per-session instances persist independently (root-scope
76
+ * instances omit it).
77
+ * @returns a fresh instance seeded from `spec.init()`.
78
+ */
79
+ create(scopeKey?: string): StoreInstance<T, A>;
80
+ }
81
+ /**
82
+ * Exclusive-store registration form: the registrant passes the factory itself
83
+ * and the framework calls it per entry x scope (no shared identity exists).
84
+ */
85
+ export type StoreFactory = () => StoreHandle<any, any>;
86
+ /** The register `store` option position: a shared handle or an exclusive factory. */
87
+ export type StoreDecl = StoreHandle<any, any> | StoreFactory;
88
+ /** Normalize a store declaration to its handle type (factories yield their return). */
89
+ export type HandleOf<H> = H extends () => infer R ? R : H;
90
+ /**
91
+ * Handle-keyed baked actions: the `actions` parameter of an inject factory
92
+ * whose registration declared a store — the same baked callback set the
93
+ * component receives via {@link PropsStore}.
94
+ */
95
+ export type BoundActions<H> = H extends StoreHandle<infer T, infer A> ? BakedActions<T, A> : never;
96
+ /**
97
+ * The store props share, derived from the declared handle: a typed selector
98
+ * hook plus the baked write set. Components never see the instance itself
99
+ * (no update/set — reads via useStore, writes via the declared actions only).
100
+ */
101
+ export type PropsStore<H> = H extends StoreHandle<infer T, infer A> ? {
102
+ useStore: SnapshotSelectorHook<T>;
103
+ actions: BakedActions<T, A>;
104
+ } : object;
105
+ /**
106
+ * The defineStore contract (implementation lives in the runtime package,
107
+ * bound to the snapshot-store engine): spec in, handle out, with T inferred
108
+ * from `init` and the actions table constrained by T.
109
+ */
110
+ export type DefineStore = <T, A extends ActionsDecl<T>>(spec: StoreSpec<T, A>) => StoreHandle<T, A>;
111
+ //# sourceMappingURL=store.d.ts.map
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@deepseek-ai/dsh-client-ui-slots",
3
+ "description": "Slot registry pure core: SlotMap declaration merging, single register composition API, four-share props types, store-seat types, renderer install seam",
4
+ "version": "0.0.1-rc.1",
5
+ "publishConfig": {
6
+ "access": "restricted"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
11
+ "directory": "packages/client/ui-slots"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./invariant": {
22
+ "types": "./lib/types/invariant.d.ts",
23
+ "default": "./lib/invariant.js"
24
+ },
25
+ "./src/*": "./src/*",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "license": "BSD-3-Clause",
29
+ "devDependencies": {
30
+ "@types/react": "~18.3.1",
31
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
32
+ "@deepseek-ai/cordis": "^4.0.1-rc.1"
33
+ },
34
+ "files": [
35
+ "lib/index.js",
36
+ "lib/invariant.js",
37
+ "lib/types/**/*.d.ts"
38
+ ],
39
+ "peerDependencies": {
40
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
41
+ "@deepseek-ai/cordis": "^4.0.1-rc.1"
42
+ }
43
+ }