@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,601 @@
1
+ /**
2
+ * Slot registry pure core. Owners declare slot
3
+ * contracts by merging into {@link SlotMap}; one `register` call contributes a
4
+ * component AND (optionally) declares child slots, a store seat, and the
5
+ * registrant's business face. Zero runtime dependencies (React types only).
6
+ *
7
+ * SlotMap and the standard-kit interfaces live directly in this entry module:
8
+ * consumer `declare module` augmentation merges with declarations lexically in
9
+ * the augmented module, not with re-exports.
10
+ */
11
+ import type { ReactNode } from 'react';
12
+ import type { HostObservable } from './renderer.ts';
13
+ import type { BoundActions, HandleOf, PropsStore, SnapshotSelectorHook, StoreDecl } from './store.ts';
14
+ export * from './store.ts';
15
+ export * from './renderer.ts';
16
+ /** Slot contract table. Owners extend via declaration merging; entries are {@link SlotEntryDef}. */
17
+ export interface SlotMap {
18
+ }
19
+ /**
20
+ * Locale namespace table. Dictionary owners extend via declaration merging
21
+ * (exactly like {@link SlotMap}, and declared in this entry module for the
22
+ * same lexical-merge reason): the key is the namespace string, the value is
23
+ * the union of its dictionary keys. Register sites declare one of these
24
+ * namespaces (`locale:`), which puts the typed `t` standard seat on the
25
+ * component props.
26
+ */
27
+ export interface LocaleNamespaceMap {
28
+ }
29
+ /**
30
+ * Translate a dictionary key with optional `{name}` template params.
31
+ * `K` narrows the accepted keys to the owning namespace's dictionary union
32
+ * (plus the shared common vocabulary where composed).
33
+ */
34
+ export type Translate<K extends string = string> = (key: K, params?: Record<string, unknown>) => string;
35
+ /**
36
+ * The shared `common` vocabulary keys as merged by the locale plugin;
37
+ * resolves to `never` in programs without the merge (this package's tests),
38
+ * keeping the union collapse harmless.
39
+ */
40
+ export type CommonKeyOf = LocaleNamespaceMap extends {
41
+ common: infer C;
42
+ } ? C & string : never;
43
+ /**
44
+ * Key domain of a namespace-bound translate: the namespace's own dictionary
45
+ * union plus the shared common vocabulary (the lookup chain consults common
46
+ * after the namespace misses).
47
+ */
48
+ export type LocaleKeysOf<N extends keyof LocaleNamespaceMap & string> = (LocaleNamespaceMap[N] & string) | CommonKeyOf;
49
+ /**
50
+ * Namespace-addressed translate — the developer-facing alias over
51
+ * {@link Translate}: `TranslateNS<'model'>` is the translate function of the
52
+ * `model` namespace (key domain = its dictionary union plus the shared
53
+ * common vocabulary), the exact type of the framework-injected `t` seat and
54
+ * of the locale service's typed `bind`.
55
+ */
56
+ export type TranslateNS<N extends keyof LocaleNamespaceMap & string> = Translate<LocaleKeysOf<N>>;
57
+ /**
58
+ * Dictionary shape for a declared namespace: exactly the keys the namespace
59
+ * merged into {@link LocaleNamespaceMap} — a missing or extra key at a typed
60
+ * registration site is a compile error.
61
+ */
62
+ export type LocaleDictOf<N extends keyof LocaleNamespaceMap & string> = Record<LocaleNamespaceMap[N] & string, string>;
63
+ /**
64
+ * Locale share of the composed component props: the framework-injected `t`
65
+ * seat, present exactly on entries whose registration declares `locale:`.
66
+ */
67
+ export type PropsLocale<N> = N extends keyof LocaleNamespaceMap & string ? {
68
+ /** Translate a dictionary key of the declared namespace (or the shared common vocabulary). */
69
+ t: TranslateNS<N>;
70
+ } : object;
71
+ /** Slot cardinality: single occupant, ordered list, key-dispatched, or selector-routed chain. */
72
+ export type SlotKind = 'single' | 'list' | 'keyed' | 'chain';
73
+ /** Slot data context: global, current-session-optional, or strict session-bound. */
74
+ export type SlotScope = 'root' | 'session-maybe' | 'session';
75
+ /**
76
+ * One SlotMap entry: kind/scope axes plus the optional owner-supplied props
77
+ * share (`owner` is what the parent passes at its renderSlot call site; the
78
+ * framework standard kit and the registrant's injected share never enter this
79
+ * table — full component props compose at the component as the four-share
80
+ * intersection, see {@link ComposedProps}).
81
+ */
82
+ export interface SlotEntryDef {
83
+ kind: SlotKind;
84
+ scope: SlotScope;
85
+ owner?: object;
86
+ /**
87
+ * Optional keyed-entry prop table. A keyed registration contributes one
88
+ * literal key and receives the corresponding prop share; ordinary owner
89
+ * props remain common to every key.
90
+ */
91
+ keyProps?: Record<string, object>;
92
+ /**
93
+ * Optional opaque context carried by one renderSlot occurrence. Only
94
+ * function-valued members of the slot-level injected hooks compartment
95
+ * receive it; the slot machinery never interprets the value.
96
+ */
97
+ hookContext?: unknown;
98
+ /**
99
+ * Optional Slot-level inject face supplied by the parent registration's
100
+ * child declaration. Every registered entry receives its bound component
101
+ * face; child registrants do not own or replace this common capability.
102
+ */
103
+ inject?: object;
104
+ }
105
+ /**
106
+ * Runtime dispatch spec for one slot, recorded from a register call's
107
+ * `children` value. The literal is compile-time checked against the SlotMap
108
+ * entry (`SlotSpec<SlotMap[P]>` in {@link ChildrenDecl}), so kind, scope, and
109
+ * any common inject face are declared at one point and validate each other.
110
+ */
111
+ export type SlotSpec<E extends SlotEntryDef> = {
112
+ kind: E['kind'];
113
+ scope: E['scope'];
114
+ } & ('inject' extends keyof E ? E extends {
115
+ inject: infer Injected extends object;
116
+ } ? {
117
+ inject: Injected;
118
+ } : {
119
+ inject?: object;
120
+ } : {
121
+ inject?: never;
122
+ });
123
+ /**
124
+ * Child-slot declaration table for register(): keys are the declared (and
125
+ * thereby render-authorized) slot names, values are their runtime dispatch
126
+ * specs. Declaring is claiming: the registering entry becomes the only entry
127
+ * allowed to render these keys.
128
+ */
129
+ export type ChildrenDecl = {
130
+ [P in keyof SlotMap & string]?: SlotSpec<SlotMap[P]>;
131
+ };
132
+ /** Owner-supplied props share for a slot key ({} for entries declaring no `owner`). */
133
+ export type OwnerOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
134
+ owner: infer O extends object;
135
+ } ? O : object;
136
+ /** Registration/dispatch key domain of one keyed slot. */
137
+ export type EntryKeyOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
138
+ kind: 'keyed';
139
+ keyProps: infer P extends object;
140
+ } ? keyof P & string : string;
141
+ /** Key-dependent props supplied by the owner at one keyed dispatch site. */
142
+ export type KeyPropsOf<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K>> = SlotMap[K] extends {
143
+ kind: 'keyed';
144
+ keyProps: infer P extends object;
145
+ } ? EntryKey extends keyof P ? P[EntryKey] extends object ? P[EntryKey] : never : never : object;
146
+ /** Opaque per-render occurrence context declared by one slot. */
147
+ export type HookContextOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
148
+ hookContext: infer Context;
149
+ } ? Context : never;
150
+ /** Common render-occurrence inject face declared by one slot. */
151
+ export type SlotInjectOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
152
+ inject: infer Injected extends object;
153
+ } ? Injected : object;
154
+ /** Scope axis of a slot key's SlotMap entry. */
155
+ export type ScopeOf<K extends keyof SlotMap & string> = SlotMap[K]['scope'];
156
+ /**
157
+ * Framework standard kit delivered to every session-scope slot component.
158
+ * Declared EMPTY here (zero-dependency layer): the runtime package merges the
159
+ * real members (`useSession` bound to the conversation snapshot and the
160
+ * framework-supplied `sessionId`) exactly as consumers merge SlotMap keys.
161
+ */
162
+ export interface SessionStandardProps {
163
+ }
164
+ /**
165
+ * Framework standard kit delivered to current-session-optional slots. Its
166
+ * hooks stay callable while no session is selected and return `undefined`
167
+ * until one becomes current; concrete members merge in at runtime packages.
168
+ */
169
+ export interface SessionMaybeStandardProps {
170
+ }
171
+ /**
172
+ * Framework standard kit delivered to EVERY slot component (the global seat).
173
+ * Declared empty here; the runtime package merges the global object-layer
174
+ * selector hooks that shared page composition consumes.
175
+ */
176
+ export interface GlobalStandardProps {
177
+ }
178
+ /**
179
+ * The session id type as the runtime's SessionStandardProps merge declares it
180
+ * (branded); falls back to `string` in programs without the merge (this
181
+ * package's own tests).
182
+ */
183
+ export type SessionIdOf = SessionStandardProps extends {
184
+ sessionId: infer S;
185
+ } ? S : string;
186
+ /**
187
+ * Runtime props share for a slot key: owner share (parent's renderSlot call
188
+ * site) + session standard kit (session scope only) + the global seat.
189
+ */
190
+ export type PropsRuntime<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K> = EntryKeyOf<K>> = OwnerOf<K> & KeyPropsOf<K, EntryKey> & SlotInjectFace<SlotInjectOf<K>> & (ScopeOf<K> extends 'session' ? SessionStandardProps : ScopeOf<K> extends 'session-maybe' ? SessionMaybeStandardProps : object) & GlobalStandardProps;
191
+ /** renderSlot dispatch options: keyed dispatch key, list filtering, and empty fallback. */
192
+ export interface RenderOpts<EntryKey extends string = string> {
193
+ entryKey?: EntryKey;
194
+ only?: string;
195
+ fallback?: ReactNode;
196
+ /** Type-erased runtime seat; PropsRenderSlots narrows or removes it per slot declaration. */
197
+ hookContext?: unknown;
198
+ }
199
+ /** renderSlotChain dispatch options. */
200
+ export interface ChainRenderOpts {
201
+ /** The owner's fallback body, rendered when every entry's selector declines. */
202
+ fallback?: ReactNode;
203
+ /**
204
+ * Keep the fallback permanently mounted: an election hides it (wrapped,
205
+ * display:none) instead of unmounting it, and the all-decline case shows it
206
+ * as-is — fallback-held state (composer drafts, DOM state) survives a
207
+ * takeover. Chain kind only. Sole consumer today: the
208
+ * 'conversation.composer' chain.
209
+ */
210
+ overlay?: boolean;
211
+ }
212
+ /**
213
+ * Chain-entry selector: the routing decision of one chain contribution.
214
+ * Runs at render time in chain order (ascending `priority`, default 0, lower
215
+ * tries first; ties keep registration = assembly order); the first non-null
216
+ * return elects its entry
217
+ * and becomes the component's `matched` prop; `null` passes to the next
218
+ * entry; all-null falls to the owner's {@link ChainRenderOpts} fallback.
219
+ * MUST be pure — a function of the owner props only, no external mutable
220
+ * reads, no side effects (the decline decision lives here, never in a
221
+ * mounted component probing its own props).
222
+ */
223
+ export type ChainSelect<O extends object, M> = (owner: O) => M | null;
224
+ /** Keys of a slot-key union whose SlotMap entry is chain-kind (renderSlotChain's dispatch domain). */
225
+ export type ChainKeysOf<S extends keyof SlotMap & string> = S extends unknown ? (SlotMap[S]['kind'] extends 'chain' ? S : never) : never;
226
+ /** Keys in a render share whose dispatch occurrence requires hookContext. */
227
+ type ContextualKeysOf<S extends keyof SlotMap & string> = S extends unknown ? (SlotMap[S] extends {
228
+ hookContext: unknown;
229
+ } ? S : never) : never;
230
+ /** Keys in a render share with the ordinary optional options bag. */
231
+ type OrdinaryKeysOf<S extends keyof SlotMap & string> = Exclude<S, ContextualKeysOf<S>>;
232
+ /**
233
+ * Plain and contextual child dispatch signatures. Keeping them as separate
234
+ * call signatures preserves ordinary renderSlot assignability while making a
235
+ * declared hookContext mandatory only for the Slot keys that need it.
236
+ */
237
+ type RenderSlotFn<S extends keyof SlotMap & string> = ([ContextualKeysOf<S>] extends [never] ? object : {
238
+ <K extends ContextualKeysOf<S>, EntryKey extends EntryKeyOf<K> = EntryKeyOf<K>>(key: K, owner: OwnerOf<K> & KeyPropsOf<K, NoInfer<EntryKey>>, opts: RenderOpts<EntryKey> & {
239
+ hookContext: HookContextOf<K>;
240
+ }): ReactNode;
241
+ }) & ([OrdinaryKeysOf<S>] extends [never] ? object : {
242
+ <K extends OrdinaryKeysOf<S>, EntryKey extends EntryKeyOf<K> = EntryKeyOf<K>>(key: K, owner: OwnerOf<K> & KeyPropsOf<K, NoInfer<EntryKey>>, opts?: Omit<RenderOpts<EntryKey>, 'hookContext'>): ReactNode;
243
+ });
244
+ /**
245
+ * Chain matched share: a chain-slot component receives its selector's
246
+ * non-null result as the framework-injected `matched` prop; other kinds add
247
+ * nothing to the composed constraint.
248
+ */
249
+ export type MatchedShare<E extends SlotEntryDef, M> = E['kind'] extends 'chain' ? {
250
+ matched: M;
251
+ } : object;
252
+ /**
253
+ * Conversation-session selector hook alias for props contracts. Wide by
254
+ * default at this dependency-inverted layer; the runtime narrows at its
255
+ * export outlet (`UseSession<ConversationSnapshot>`).
256
+ */
257
+ export type UseSession<Snap extends object = object> = SnapshotSelectorHook<Snap>;
258
+ /** Props of the standard-kit SessionProvider seat (render-prop form). */
259
+ export interface SessionAreaProps {
260
+ /** No-session body (also covers a current id whose session cannot be resolved). */
261
+ empty?: (() => ReactNode) | undefined;
262
+ /** Session body; the framework remounts it per session (key=sessionId). */
263
+ children: (sessionId: SessionIdOf) => ReactNode;
264
+ }
265
+ /**
266
+ * Framework-wired session area component. It subscribes to runtime-owned
267
+ * session selection and is injected into entries that declare session-scoped
268
+ * children; business code does not import it directly.
269
+ */
270
+ export type SessionProviderComponent = (props: SessionAreaProps) => ReactNode;
271
+ /**
272
+ * Child-slot render share: `renderSlot` statically narrowed to the entry's
273
+ * declared children keys. Delegation is plain props passing (hand
274
+ * `props.renderSlot` down); the authorizing identity stays the registering
275
+ * entry. `__renders` is a phantom variance anchor (never materialized):
276
+ * generic method signatures compare loosely across differing key unions, so
277
+ * this contravariant marker is what actually enforces "component key set ⊆
278
+ * children declaration" at the register call site.
279
+ */
280
+ export type PropsRenderSlots<S extends keyof SlotMap & string> = {
281
+ /**
282
+ * Render a declared non-chain child slot (chain keys dispatch through
283
+ * `renderSlotChain` — their routing lives in entry selectors).
284
+ * @param key - declared child key.
285
+ * @param owner - owner props share for that key (decided at the render site).
286
+ * @param opts - kind dispatch options.
287
+ * @returns rendered node(s).
288
+ */
289
+ renderSlot: RenderSlotFn<Exclude<S, ChainKeysOf<S>>>;
290
+ readonly __renders?: ((key: S) => void) | undefined;
291
+ } & ([ChainKeysOf<S>] extends [never] ? object : {
292
+ /**
293
+ * Render a declared chain child slot: entry selectors run in chain order
294
+ * over `owner`; the first non-null match renders its component with the
295
+ * selector result injected as `matched`; all-null renders `opts.fallback`.
296
+ * @param key - declared chain child key.
297
+ * @param owner - owner props share (the selectors' routing input).
298
+ * @param opts - fallback body for the all-null case.
299
+ * @returns rendered node(s).
300
+ */
301
+ renderSlotChain: <K extends ChainKeysOf<S>>(key: K, owner: OwnerOf<K>, opts?: ChainRenderOpts) => ReactNode;
302
+ }) & ('session' extends ScopeOf<S> ? {
303
+ SessionProvider: SessionProviderComponent;
304
+ } : object);
305
+ /**
306
+ * Registration-position component shape: the bare call signature, so composed
307
+ * constraints check through clean parameter contravariance (FC statics add
308
+ * covariant noise rejecting legitimate narrowings).
309
+ */
310
+ export type SlotComponent<P> = (props: P) => ReactNode;
311
+ /**
312
+ * Registrant hooks compartment: bare observable sources (getSnapshot +
313
+ * subscribe pairs) supplied under the reserved `hooks` key of an entry's
314
+ * inject face. These retain the original source-to-selector binding and do
315
+ * not participate in render-occurrence context.
316
+ */
317
+ export type HooksSources = Record<string, HostObservable<unknown>>;
318
+ /** Framework-owned props visible while a slot-level contextual Hook is bound. */
319
+ export type StandardPropsOf<K extends keyof SlotMap & string> = (ScopeOf<K> extends 'session' ? SessionStandardProps : ScopeOf<K> extends 'session-maybe' ? SessionMaybeStandardProps : object) & GlobalStandardProps;
320
+ /**
321
+ * One function-valued slot-level inject.hooks member. The factory is pure and
322
+ * returns the actual custom Hook; it must not invoke a Hook while being bound.
323
+ */
324
+ export type SlotHookFactory<K extends keyof SlotMap & string, Hook extends (...args: never[]) => unknown> = (standard: StandardPropsOf<K>, hookContext: HookContextOf<K>) => Hook;
325
+ /** Component-side Hook produced from one slot-level inject.hooks member. */
326
+ type BoundHookOf<Definition> = Definition extends HostObservable<infer Snapshot> ? SnapshotSelectorHook<Snapshot> : Definition extends (...args: never[]) => infer Hook ? Hook extends (...args: never[]) => unknown ? Hook : never : never;
327
+ /**
328
+ * Selector-hook share synthesized from a hooks compartment: each source
329
+ * `name` becomes a `use<Name>` selector hook over its snapshot type.
330
+ */
331
+ export type PropsSlotHooks<HS extends object> = {
332
+ [N in keyof HS & string as `use${Capitalize<N>}`]: BoundHookOf<HS[N]>;
333
+ };
334
+ /** Component-side view of a slot dispatcher's common inject face. */
335
+ export type SlotInjectFace<I extends object> = I extends {
336
+ hooks: infer HS extends object;
337
+ } ? Omit<I, 'hooks'> & PropsSlotHooks<HS> : I;
338
+ /** Selector-hook share synthesized from an entry inject hooks compartment. */
339
+ export type PropsHooks<HS extends HooksSources> = {
340
+ [N in keyof HS & string as `use${Capitalize<N>}`]: SnapshotSelectorHook<HS[N] extends HostObservable<infer T> ? T : never>;
341
+ };
342
+ /**
343
+ * The component-side view of an inject face: the reserved `hooks`
344
+ * compartment (when declared) arrives as bound `use<Name>` selector hooks;
345
+ * every other member passes through verbatim.
346
+ */
347
+ export type InjectFace<I extends object> = I extends {
348
+ hooks: infer HS extends HooksSources;
349
+ } ? Omit<I, 'hooks'> & PropsHooks<HS> : I;
350
+ /**
351
+ * The composed component props intersection: runtime share (SlotMap) +
352
+ * child-render share (children declaration) + store share (declared handle) +
353
+ * the registrant's injected business face (its hooks compartment bound, see
354
+ * {@link InjectFace}) + the locale `t` seat (declared namespace, see
355
+ * {@link PropsLocale}). Each share derives from its single source of truth;
356
+ * components reference this composition, never re-type it.
357
+ */
358
+ export type ComposedProps<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K>, S extends keyof SlotMap & string, H, I extends object, M = never, N = undefined> = PropsRuntime<K, EntryKey> & PropsRenderSlots<S> & PropsStore<H> & InjectFace<I> & MatchedShare<SlotMap[K], M> & PropsLocale<N>;
359
+ /**
360
+ * Inject factory parameter list, derived from the registration's declaration:
361
+ * strict session slots receive a definite framework-resolved `sessionId`;
362
+ * session-maybe slots receive the current id or `undefined`; a declared store
363
+ * appends the baked `actions` (the same callbacks the component receives).
364
+ * Business data access happens through the apply closure's ctx — no binding
365
+ * object parameter exists.
366
+ */
367
+ export type InjectParams<K extends keyof SlotMap & string, H> = ScopeOf<K> extends 'session' ? ([H] extends [StoreDecl] ? [sessionId: SessionIdOf, actions: BoundActions<HandleOf<H>>] : [sessionId: SessionIdOf]) : ScopeOf<K> extends 'session-maybe' ? ([H] extends [StoreDecl] ? [sessionId: SessionIdOf | undefined, actions: BoundActions<HandleOf<H>> | undefined] : [sessionId: SessionIdOf | undefined]) : ([H] extends [StoreDecl] ? [actions: BoundActions<HandleOf<H>>] : []);
368
+ /**
369
+ * A list-entry display label: a plain string, or a thunk re-evaluated per
370
+ * read so registration-time text (nav rows, tabs) follows the active locale
371
+ * without re-registration. Owners resolve through {@link resolveSlotLabel}.
372
+ */
373
+ export type SlotLabel = string | (() => string);
374
+ /** Kind shape fields carried in register options (keyed dispatch key; list id/order/label; chain select/priority). */
375
+ export type KindOptions<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K>, M = never> = SlotMap[K]['kind'] extends 'keyed' ? {
376
+ key: EntryKey;
377
+ } : SlotMap[K]['kind'] extends 'list' ? {
378
+ id: string;
379
+ order?: number;
380
+ label?: SlotLabel;
381
+ } : SlotMap[K]['kind'] extends 'chain' ? {
382
+ /** Routing selector, mandatory on chain entries; `M` (the component's `matched` prop) infers from its return. */
383
+ select: ChainSelect<SlotMap[K] extends {
384
+ owner: infer O extends object;
385
+ } ? O : object, M>;
386
+ /** Explicit chain position (ascending, default 0, lower tries first); ties keep registration = assembly order. */
387
+ priority?: number;
388
+ } : object;
389
+ /**
390
+ * Compile-time presence check: an entry declaring children MUST consume
391
+ * `renderSlot` (or `renderSlotChain` when its only children are chain slots)
392
+ * — declaring is claiming; an entry that does not render its children should
393
+ * not declare them. Evaluates to an unsatisfiable intersection member naming
394
+ * the declared keys when violated.
395
+ */
396
+ type RendersCheck<C, D> = [
397
+ keyof D & keyof SlotMap & string
398
+ ] extends [never] ? unknown : C extends (props: infer P) => ReactNode ? ('renderSlot' extends keyof P ? unknown : 'renderSlotChain' extends keyof P ? unknown : {
399
+ 'children declared but the component consumes no renderSlot': keyof D & keyof SlotMap & string;
400
+ }) : unknown;
401
+ /** Common register options share (see {@link SlotCore.register} for semantics). */
402
+ type BaseOptions<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K>, D extends ChildrenDecl, H, M = never, N = undefined> = {
403
+ /** Target slot key (the entry contributes INTO this slot). */
404
+ name: K;
405
+ /** Child-slot declaration + render authorization + runtime spec, in one table. */
406
+ children?: D;
407
+ /** Store seat: a shared handle (apply-constructed) or an exclusive factory (framework-called per entry x scope). */
408
+ store?: H;
409
+ /**
410
+ * Dictionary namespace of this entry's copy. Declaring it puts the
411
+ * framework-synthesized `t` seat (typed to the namespace's dictionary
412
+ * union) on the component props; rendering requires an installed locale
413
+ * face — fails loud otherwise.
414
+ */
415
+ locale?: N;
416
+ /** Registrant identity label for diagnostics (the runtime Service wrapper stamps the caller's fiber name). */
417
+ registrant?: string;
418
+ } & KindOptions<K, EntryKey, M>;
419
+ /**
420
+ * One stored registration, as recorded by the core and read by the render
421
+ * machinery (type-erased at this boundary; the registration contract already proved
422
+ * the shares against the component).
423
+ */
424
+ export interface StoredEntry {
425
+ component: unknown;
426
+ options: {
427
+ key?: string;
428
+ id?: string;
429
+ order?: number;
430
+ label?: SlotLabel;
431
+ priority?: number;
432
+ };
433
+ /** Chain routing selector (type-erased like `inject`; present exactly on chain-slot entries). */
434
+ select?: ((owner: never) => unknown) | undefined;
435
+ /** Registrant business face; positional params derive from the declaration (sessionId?, actions?). */
436
+ inject?: ((...args: never[]) => Record<string, unknown>) | undefined;
437
+ /** Child-slot declaration table (declaration + authorization + runtime spec in one). */
438
+ children?: Readonly<Record<string, SlotSpec<SlotEntryDef>>> | undefined;
439
+ /** Declared store seat (instance resolution and lifecycle live with the host machinery). */
440
+ store?: StoreDecl | undefined;
441
+ /** Declared dictionary namespace (the render machinery synthesizes the `t` seat from it). */
442
+ locale?: string | undefined;
443
+ /** Diagnostics label of who registered. */
444
+ registrant?: string | undefined;
445
+ }
446
+ /**
447
+ * Resolve a possibly-thunked list label at read time (thunks follow the
448
+ * active locale; owners projecting ledger rows call this instead of reading
449
+ * `options.label` raw).
450
+ * @param label - the stored label.
451
+ * @returns the display string, or undefined when the entry declared none.
452
+ */
453
+ export declare function resolveSlotLabel(label: SlotLabel | undefined): string | undefined;
454
+ /**
455
+ * Pure slot registry (no cordis; event emission and the renderer installation contract
456
+ * live in the runtime Service wrapper).
457
+ *
458
+ * The 'root' slot is the one a-priori declaration, seeded at construction
459
+ * (single/root, declared by the framework) — the render tree's root hole.
460
+ *
461
+ * Change propagation contract: versions bump and {@link SlotCore.onMutate}
462
+ * fires synchronously per mutation (registry state is consistent when they
463
+ * fire); {@link SlotCore.subscribeDeclaration} fires synchronously for each
464
+ * declaration lifetime boundary; {@link SlotCore.subscribe} notifications
465
+ * batch per microtask, so N same-tick mutations produce one notification per
466
+ * touched key.
467
+ */
468
+ export declare class SlotCore {
469
+ private records;
470
+ private mutateListeners;
471
+ /** Shared-handle scope ledger: handle → the scope it first mounted under + live mount count. */
472
+ private handleScopes;
473
+ private dirty;
474
+ private flushScheduled;
475
+ constructor();
476
+ /**
477
+ * Contribute a component to a declared slot and (optionally) declare child
478
+ * slots, a store seat, and the registrant's business face.
479
+ *
480
+ * Load-time validation (misconfiguration fails loud; the render hot path
481
+ * re-checks nothing): registering into an undeclared slot throws; declaring
482
+ * an already-declared child key throws (one declarer per slot — the message
483
+ * names the first declarer); mounting one shared store handle under slots
484
+ * of different scopes throws. Kind constraints: single — duplicate
485
+ * registration throws; keyed — missing/duplicate `key` throws; list —
486
+ * missing/duplicate `id` throws; chain — missing `select` throws (the
487
+ * selector is the entry's routing seat, see {@link ChainSelect}).
488
+ *
489
+ * Lifecycle: the disposer removes the contribution AND collapses every
490
+ * declared child slot (child entries clear recursively; their stale
491
+ * disposers become no-ops) — one lifecycle axis, no dangling state.
492
+ *
493
+ * @param options - registration options: target `name`, `children`
494
+ * declaration table, `store` seat, `inject` business-face factory, kind
495
+ * shape fields (keyed `key`; list `id`/`order`/`label`).
496
+ * @param component - component honoring the four-share composed props
497
+ * contract ({@link ComposedProps}); checked at this call site.
498
+ * @returns disposer removing the registration and its declarations
499
+ * (idempotent; stale disposers after a cascade are no-ops).
500
+ */
501
+ register<K extends keyof SlotMap & string, const EntryKey extends EntryKeyOf<K> = EntryKeyOf<K>, const D extends ChildrenDecl = Record<never, never>, H extends StoreDecl | undefined = undefined, M = never, N extends (keyof LocaleNamespaceMap & string) | undefined = undefined, C extends SlotComponent<never> = SlotComponent<never>>(options: BaseOptions<K, EntryKey, D, H, M, N> & {
502
+ inject?: undefined;
503
+ }, component: C & SlotComponent<ComposedProps<K, NoInfer<EntryKey>, keyof NoInfer<D> & keyof SlotMap & string, HandleOf<NoInfer<H>>, object, NoInfer<M>, NoInfer<N>>> & RendersCheck<C, D>): () => void;
504
+ /**
505
+ * Inject-bearing overload: identical semantics to the overload above, plus
506
+ * the registrant's business face — `I` is inferred from the inject
507
+ * factory's return and joins the component's composed-props constraint
508
+ * (factory parameters derive from the declaration, {@link InjectParams}).
509
+ * @param options - registration options plus the `inject` business-face factory.
510
+ * @param component - component honoring the four-share composed props
511
+ * contract including the inject share `I`.
512
+ * @returns disposer removing the registration and its declarations.
513
+ */
514
+ register<K extends keyof SlotMap & string, I extends object, const EntryKey extends EntryKeyOf<K> = EntryKeyOf<K>, const D extends ChildrenDecl = Record<never, never>, H extends StoreDecl | undefined = undefined, M = never, N extends (keyof LocaleNamespaceMap & string) | undefined = undefined, C extends SlotComponent<never> = SlotComponent<never>>(options: BaseOptions<K, EntryKey, D, H, M, N> & {
515
+ inject: (...args: InjectParams<K, H>) => I;
516
+ }, component: C & SlotComponent<ComposedProps<K, NoInfer<EntryKey>, keyof NoInfer<D> & keyof SlotMap & string, HandleOf<NoInfer<H>>, I, NoInfer<M>, NoInfer<N>>> & RendersCheck<C, D>): () => void;
517
+ /**
518
+ * Whether a previously obtained entry is still registered (the render
519
+ * machinery's stale-authorization probe: a retained renderSlot binding
520
+ * whose entry left the ledger must not render).
521
+ * @param entry - a previously read entry.
522
+ * @returns false once the entry's registration was disposed.
523
+ */
524
+ isLive(entry: StoredEntry): boolean;
525
+ /**
526
+ * Snapshot the registered entries for a key. Returns the cached array
527
+ * reference (stable between mutations — safe as a uSES getSnapshot source);
528
+ * empty for keys not (or no longer) declared, so renderers may probe ahead
529
+ * of plugin load order.
530
+ * @param key - slot key (dynamic: the render machinery holds keys as strings).
531
+ * @returns entries in registration (list: order) sequence.
532
+ */
533
+ entries(key: string): readonly StoredEntry[];
534
+ /**
535
+ * Look up a slot's declared spec, narrowed by the SlotMap key.
536
+ * @param key - SlotMap key.
537
+ * @returns the spec, or undefined while undeclared.
538
+ */
539
+ spec<K extends keyof SlotMap & string>(key: K): SlotSpec<SlotMap[K]> | undefined;
540
+ /**
541
+ * Dynamic-key escape hatch for spec lookup — renderers resolving keys they
542
+ * only hold as strings (generic dispatch) use this wide form; statically
543
+ * keyed callers use {@link SlotCore.spec}.
544
+ * @param key - candidate slot key.
545
+ * @returns the wide-typed spec, or undefined while undeclared.
546
+ */
547
+ specDynamic(key: string): SlotSpec<SlotEntryDef> | undefined;
548
+ /**
549
+ * Read the declaration lifetime of a key. Entry additions and removals do
550
+ * not change it; declaration creation and collapse each advance it.
551
+ * @param key - slot key.
552
+ * @returns monotonic epoch (0 before the first declaration).
553
+ */
554
+ declarationEpoch(key: string): number;
555
+ /**
556
+ * Subscribe to registration changes for a key (microtask-batched).
557
+ * Subscribing ahead of declaration is allowed; the declaration notifies.
558
+ * @param key - slot key.
559
+ * @param fn - change callback.
560
+ * @returns unsubscribe.
561
+ */
562
+ subscribe(key: string, fn: () => void): () => void;
563
+ /**
564
+ * Subscribe to declaration lifetime boundaries for a key. Notifications
565
+ * are synchronous so declaration teardown finishes before a subsequent
566
+ * same-tick registration can observe stale resources. Ordinary entry
567
+ * mutations do not notify this surface. A children table commits every
568
+ * sibling declaration before its first notification.
569
+ * @param key - slot key.
570
+ * @param fn - declaration or collapse callback.
571
+ * @returns unsubscribe.
572
+ */
573
+ subscribeDeclaration(key: string, fn: () => void): () => void;
574
+ /**
575
+ * Monotonic version for a key, bumped synchronously per mutation so a
576
+ * uSES getSnapshot read is never stale when its batched notification lands.
577
+ * @param key - slot key.
578
+ * @returns current version (0 for untouched keys).
579
+ */
580
+ getVersion(key: string): number;
581
+ /**
582
+ * Hook every mutation (the runtime Service wrapper bridges this to ctx.emit).
583
+ * Fires synchronously per mutation, unbatched — event semantics need one
584
+ * emission per change.
585
+ * @param fn - called with the mutated key.
586
+ * @returns unsubscribe.
587
+ */
588
+ onMutate(fn: (key: string) => void): () => void;
589
+ /**
590
+ * Cascade for a removed entry: release its store mount and collapse every
591
+ * child slot it declared — specs clear, contributions empty (their stale
592
+ * disposers no-op), recursively down the declaration tree. One lifecycle
593
+ * axis: ledger rows, slots, contributions, and store mounts die together.
594
+ */
595
+ private releaseEntry;
596
+ private record;
597
+ private markDirty;
598
+ private notifyDeclaration;
599
+ private flush;
600
+ }
601
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Package-owned invariant companion for `@deepseek-ai/dsh-client-ui-slots`.
3
+ * @module @deepseek-ai/dsh-client-ui-slots/invariant
4
+ */
5
+ import type { Context } from '@deepseek-ai/cordis';
6
+ /** Cordis companion plugin name. */
7
+ export declare const name = "client-ui-slots-invariant";
8
+ /** Service required before the companion can reserve package ownership. */
9
+ export declare const inject: string[];
10
+ /**
11
+ * Register this package's invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the installed registration's disposer after setup succeeds.
14
+ */
15
+ export declare const apply: (ctx: Context) => Promise<() => void>;
16
+ //# sourceMappingURL=invariant.d.ts.map