@x1a0f3n9/dsh-client-ui-slots 0.1.5-rc.2

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,740 @@
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 { BoundActions, HandleOf, PropsStore, SnapshotSelectorHook, StoreDecl } from '@x1a0f3n9/dsh-client-store';
13
+ import type { HostObservable, KeyedStandardSource } from './renderer.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
+ * Resource protocol (URL scheme) → the value its provider streams. Declared
31
+ * empty here, the zero-dependency merge point; each protocol owner merges its
32
+ * own member (`file`, later `chat`), and `useResource<P>(address)` narrows its
33
+ * value by `P`. The resource service itself lives in `dsh-client-resources`.
34
+ */
35
+ export interface ResourceProtocolMap {
36
+ }
37
+ /**
38
+ * Translate a dictionary key with optional `{name}` template params.
39
+ * `K` narrows the accepted keys to the owning namespace's dictionary union
40
+ * (plus the shared common vocabulary where composed).
41
+ */
42
+ export type Translate<K extends string = string> = (key: K, params?: Record<string, unknown>) => string;
43
+ /**
44
+ * The shared `common` vocabulary keys as merged by the locale plugin;
45
+ * resolves to `never` in programs without the merge (this package's tests),
46
+ * keeping the union collapse harmless.
47
+ */
48
+ export type CommonKeyOf = LocaleNamespaceMap extends {
49
+ common: infer C;
50
+ } ? C & string : never;
51
+ /**
52
+ * Key domain of a namespace-bound translate: the namespace's own dictionary
53
+ * union plus the shared common vocabulary (the lookup chain consults common
54
+ * after the namespace misses).
55
+ */
56
+ export type LocaleKeysOf<N extends keyof LocaleNamespaceMap & string> = (LocaleNamespaceMap[N] & string) | CommonKeyOf;
57
+ /**
58
+ * Namespace-addressed translate — the developer-facing alias over
59
+ * {@link Translate}: `TranslateNS<'model'>` is the translate function of the
60
+ * `model` namespace (key domain = its dictionary union plus the shared
61
+ * common vocabulary), the exact type of the framework-injected `t` seat and
62
+ * of the locale service's typed `bind`.
63
+ */
64
+ export type TranslateNS<N extends keyof LocaleNamespaceMap & string> = Translate<LocaleKeysOf<N>>;
65
+ /**
66
+ * Dictionary shape for a declared namespace: exactly the keys the namespace
67
+ * merged into {@link LocaleNamespaceMap} — a missing or extra key at a typed
68
+ * registration site is a compile error.
69
+ */
70
+ export type LocaleDictOf<N extends keyof LocaleNamespaceMap & string> = Record<LocaleNamespaceMap[N] & string, string>;
71
+ /**
72
+ * Locale share of the composed component props: the framework-injected `t`
73
+ * seat, present exactly on entries whose registration declares `locale:`.
74
+ */
75
+ export type PropsLocale<N> = N extends keyof LocaleNamespaceMap & string ? {
76
+ /** Translate a dictionary key of the declared namespace (or the shared common vocabulary). */
77
+ t: TranslateNS<N>;
78
+ } : object;
79
+ /** Slot cardinality: single occupant, ordered list, key-dispatched, or selector-routed chain. */
80
+ export type SlotKind = 'single' | 'list' | 'keyed' | 'chain';
81
+ /** Slot data context: global, current-session-optional, or strict session-bound. */
82
+ export type SlotScope = 'root' | 'session-maybe' | 'session';
83
+ /**
84
+ * One SlotMap entry: kind/scope axes plus the optional owner-supplied props
85
+ * share (`owner` is what the parent passes at its renderSlot call site; the
86
+ * framework standard kit and the registrant's injected share never enter this
87
+ * table — full component props compose at the component as the four-share
88
+ * intersection, see {@link ComposedProps}).
89
+ */
90
+ export interface SlotEntryDef {
91
+ kind: SlotKind;
92
+ scope: SlotScope;
93
+ owner?: object;
94
+ /**
95
+ * Optional keyed-entry prop table. A keyed registration contributes one
96
+ * literal key and receives the corresponding prop share; ordinary owner
97
+ * props remain common to every key.
98
+ */
99
+ keyProps?: Record<string, object>;
100
+ /**
101
+ * Optional opaque context carried by one renderSlot occurrence. Only
102
+ * function-valued members of the slot-level injected hooks compartment
103
+ * receive it; the slot machinery never interprets the value.
104
+ */
105
+ hookContext?: unknown;
106
+ /**
107
+ * Optional Slot-level inject face supplied by the parent registration's
108
+ * child declaration. Every registered entry receives its bound component
109
+ * face; child registrants do not own or replace this common capability.
110
+ */
111
+ inject?: object;
112
+ }
113
+ /**
114
+ * Runtime dispatch spec for one slot, recorded from a register call's
115
+ * `children` value. The literal is compile-time checked against the SlotMap
116
+ * entry (`SlotSpec<SlotMap[P]>` in {@link ChildrenDecl}), so kind, scope, and
117
+ * any common inject face are declared at one point and validate each other.
118
+ */
119
+ export type SlotSpec<E extends SlotEntryDef> = {
120
+ kind: E['kind'];
121
+ scope: E['scope'];
122
+ } & ('inject' extends keyof E ? E extends {
123
+ inject: infer Injected extends object;
124
+ } ? {
125
+ inject: Injected;
126
+ } : {
127
+ inject?: object;
128
+ } : {
129
+ inject?: never;
130
+ });
131
+ /**
132
+ * Child-slot declaration table for register(): keys are the declared (and
133
+ * thereby render-authorized) slot names, values are their runtime dispatch
134
+ * specs. Declaring is claiming: the registering entry becomes the only entry
135
+ * allowed to render these keys.
136
+ */
137
+ export type ChildrenDecl = {
138
+ [P in keyof SlotMap & string]?: SlotSpec<SlotMap[P]>;
139
+ };
140
+ /** Owner-supplied props share for a slot key ({} for entries declaring no `owner`). */
141
+ export type OwnerOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
142
+ owner: infer O extends object;
143
+ } ? O : object;
144
+ /** Registration/dispatch key domain of one keyed slot. */
145
+ export type EntryKeyOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
146
+ kind: 'keyed';
147
+ keyProps: infer P extends object;
148
+ } ? keyof P & string : string;
149
+ /** Key-dependent props supplied by the owner at one keyed dispatch site. */
150
+ export type KeyPropsOf<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K>> = SlotMap[K] extends {
151
+ kind: 'keyed';
152
+ keyProps: infer P extends object;
153
+ } ? EntryKey extends keyof P ? P[EntryKey] extends object ? P[EntryKey] : never : never : object;
154
+ /** Opaque per-render occurrence context declared by one slot. */
155
+ export type HookContextOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
156
+ hookContext: infer Context;
157
+ } ? Context : never;
158
+ /** Common render-occurrence inject face declared by one slot. */
159
+ export type SlotInjectOf<K extends keyof SlotMap & string> = SlotMap[K] extends {
160
+ inject: infer Injected extends object;
161
+ } ? Injected : object;
162
+ /** Scope axis of a slot key's SlotMap entry. */
163
+ export type ScopeOf<K extends keyof SlotMap & string> = SlotMap[K]['scope'];
164
+ /**
165
+ * Framework standard kit delivered to every session-scope slot component.
166
+ * Declared empty here (zero-dependency layer): `ui-session` merges the
167
+ * Session lifecycle hook, projection hook, and Session identity; domain UI
168
+ * adapters merge their own standard hooks exactly as consumers merge SlotMap keys.
169
+ */
170
+ export interface SessionStandardProps {
171
+ }
172
+ /**
173
+ * Framework standard kit delivered to current-session-optional slots. Its
174
+ * hooks stay callable while no session is selected and return `undefined`
175
+ * until one becomes current; `ui-session` and domain UI adapters merge the
176
+ * concrete members.
177
+ */
178
+ export interface SessionMaybeStandardProps {
179
+ }
180
+ /**
181
+ * Framework standard kit delivered to EVERY slot component (the global seat).
182
+ * Declared empty here; each owning UI adapter merges the global selector hooks
183
+ * that shared page composition consumes.
184
+ */
185
+ export interface GlobalStandardProps {
186
+ }
187
+ /**
188
+ * The session id type as `ui-session`'s SessionStandardProps merge declares it
189
+ * (branded); falls back to `string` in programs without the merge (this
190
+ * package's own tests).
191
+ */
192
+ export type SessionIdOf = SessionStandardProps extends {
193
+ sessionId: infer S;
194
+ } ? S : string;
195
+ /**
196
+ * Runtime props share for a slot key: owner share (parent's renderSlot call
197
+ * site) + session standard kit (session scope only) + the global seat.
198
+ */
199
+ 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;
200
+ /** renderSlot dispatch options: keyed dispatch key, list filtering, and empty fallback. */
201
+ export interface RenderOpts<EntryKey extends string = string> {
202
+ entryKey?: EntryKey;
203
+ only?: string;
204
+ fallback?: ReactNode;
205
+ /** Type-erased runtime seat; PropsRenderSlots narrows or removes it per slot declaration. */
206
+ hookContext?: unknown;
207
+ }
208
+ /** renderSlotChain dispatch options. */
209
+ export interface ChainRenderOpts {
210
+ /** The owner's fallback body, rendered when every entry's selector declines. */
211
+ fallback?: ReactNode;
212
+ /** Render only the owner fallback without resolving or dispatching the chain's scope. */
213
+ fallbackOnly?: boolean;
214
+ /**
215
+ * Keep the fallback permanently mounted: an election hides it (wrapped,
216
+ * display:none) instead of unmounting it, and the all-decline case shows it
217
+ * as-is — fallback-held state (composer drafts, DOM state) survives a
218
+ * takeover. Chain kind only; the sole consumer is the
219
+ * `conversation.composer` chain.
220
+ */
221
+ overlay?: boolean;
222
+ }
223
+ /**
224
+ * Chain-entry selector: the routing decision of one chain contribution.
225
+ * Runs at render time in chain order (ascending `priority`, default 0, lower
226
+ * tries first; ties keep registration = assembly order); the first non-null
227
+ * return elects its entry
228
+ * and becomes the component's `matched` prop; `null` passes to the next
229
+ * entry; all-null falls to the owner's {@link ChainRenderOpts} fallback.
230
+ * MUST be pure — a function of the owner props only, no external mutable
231
+ * reads, no side effects (the decline decision lives here, never in a
232
+ * mounted component probing its own props).
233
+ */
234
+ export type ChainSelect<O extends object, M> = (owner: O) => M | null;
235
+ /** Keys of a slot-key union whose SlotMap entry is chain-kind (renderSlotChain's dispatch domain). */
236
+ export type ChainKeysOf<S extends keyof SlotMap & string> = S extends unknown ? (SlotMap[S]['kind'] extends 'chain' ? S : never) : never;
237
+ /** Keys in a render share whose dispatch occurrence requires hookContext. */
238
+ type ContextualKeysOf<S extends keyof SlotMap & string> = S extends unknown ? (SlotMap[S] extends {
239
+ hookContext: unknown;
240
+ } ? S : never) : never;
241
+ /** Keys in a render share with the ordinary optional options bag. */
242
+ type OrdinaryKeysOf<S extends keyof SlotMap & string> = Exclude<S, ContextualKeysOf<S>>;
243
+ /**
244
+ * Plain and contextual child dispatch signatures. Keeping them as separate
245
+ * call signatures preserves ordinary renderSlot assignability while making a
246
+ * declared hookContext mandatory only for the Slot keys that need it.
247
+ */
248
+ type RenderSlotFn<S extends keyof SlotMap & string> = ([ContextualKeysOf<S>] extends [never] ? object : {
249
+ <K extends ContextualKeysOf<S>, EntryKey extends EntryKeyOf<K> = EntryKeyOf<K>>(key: K, owner: OwnerOf<K> & KeyPropsOf<K, NoInfer<EntryKey>>, opts: RenderOpts<EntryKey> & {
250
+ hookContext: HookContextOf<K>;
251
+ }): ReactNode;
252
+ }) & ([OrdinaryKeysOf<S>] extends [never] ? object : {
253
+ <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;
254
+ });
255
+ /**
256
+ * Chain matched share: a chain-slot component receives its selector's
257
+ * non-null result as the framework-injected `matched` prop; other kinds add
258
+ * nothing to the composed constraint.
259
+ */
260
+ export type MatchedShare<E extends SlotEntryDef, M> = E['kind'] extends 'chain' ? {
261
+ matched: M;
262
+ } : object;
263
+ /** Props of the standard-kit SessionProvider seat. */
264
+ export interface SessionAreaProps {
265
+ /** No-session body (also covers a current id whose session cannot be resolved). */
266
+ empty?: (() => ReactNode) | undefined;
267
+ /** Session body; the framework remounts it per session identity. */
268
+ children: ReactNode;
269
+ }
270
+ /**
271
+ * Framework-wired session area component. `ui-session` supplies the current
272
+ * Controller binding through the renderer scope adapter; entries that declare
273
+ * session-scoped children receive this component without importing it.
274
+ */
275
+ export type SessionProviderComponent = (props: SessionAreaProps) => ReactNode;
276
+ /**
277
+ * Child-slot render share: `renderSlot` statically narrowed to the entry's
278
+ * declared children keys. Delegation is plain props passing (hand
279
+ * `props.renderSlot` down); the authorizing identity stays the registering
280
+ * entry. `__renders` is a phantom variance anchor (never materialized):
281
+ * generic method signatures compare loosely across differing key unions, so
282
+ * this contravariant marker is what actually enforces "component key set ⊆
283
+ * children declaration" at the register call site.
284
+ */
285
+ export type PropsRenderSlots<S extends keyof SlotMap & string> = {
286
+ /**
287
+ * Render a declared non-chain child slot (chain keys dispatch through
288
+ * `renderSlotChain` — their routing lives in entry selectors).
289
+ * @param key - declared child key.
290
+ * @param owner - owner props share for that key (decided at the render site).
291
+ * @param opts - kind dispatch options.
292
+ * @returns rendered node(s).
293
+ */
294
+ renderSlot: RenderSlotFn<Exclude<S, ChainKeysOf<S>>>;
295
+ readonly __renders?: ((key: S) => void) | undefined;
296
+ } & ([ChainKeysOf<S>] extends [never] ? object : {
297
+ /**
298
+ * Render a declared chain child slot: entry selectors run in chain order
299
+ * over `owner`; the first non-null match renders its component with the
300
+ * selector result injected as `matched`; all-null renders `opts.fallback`.
301
+ * @param key - declared chain child key.
302
+ * @param owner - owner props share (the selectors' routing input).
303
+ * @param opts - fallback body for the all-null case.
304
+ * @returns rendered node(s).
305
+ */
306
+ renderSlotChain: <K extends ChainKeysOf<S>>(key: K, owner: OwnerOf<K>, opts?: ChainRenderOpts) => ReactNode;
307
+ }) & ('session' extends ScopeOf<S> ? {
308
+ SessionProvider: SessionProviderComponent;
309
+ } : object);
310
+ /**
311
+ * Registration-position component shape: the bare call signature, so composed
312
+ * constraints check through clean parameter contravariance (FC statics add
313
+ * covariant noise rejecting legitimate narrowings).
314
+ */
315
+ export type SlotComponent<P> = (props: P) => ReactNode;
316
+ /**
317
+ * Registrant hooks compartment: bare observable sources (getSnapshot +
318
+ * subscribe pairs) supplied under the reserved `hooks` key of an entry's
319
+ * inject face. These retain the original source-to-selector binding and do
320
+ * not participate in render-occurrence context.
321
+ */
322
+ export type HooksSources = Record<string, HostObservable<unknown>>;
323
+ /** Registrant keyed-hooks compartment: stable key-to-observable resolvers. */
324
+ export type KeyedHooksSources = Record<string, KeyedStandardSource>;
325
+ /** Selector Hook over an open family of keyed observable sources. */
326
+ export type KeyedSnapshotSelectorHook<Snapshot> = {
327
+ /** @param key - source key. @returns the current value, or absence when the source is unavailable. */
328
+ (key: string): Snapshot | undefined;
329
+ /**
330
+ * @param key - source key.
331
+ * @param selector - projection over the current keyed value.
332
+ * @param equal - optional selected-value equality.
333
+ * @returns the selected value.
334
+ */
335
+ <Selected>(key: string, selector: (value: Snapshot | undefined) => Selected, equal?: (left: Selected, right: Selected) => boolean): Selected;
336
+ };
337
+ /** Framework-owned props visible while a slot-level contextual Hook is bound. */
338
+ export type StandardPropsOf<K extends keyof SlotMap & string> = (ScopeOf<K> extends 'session' ? SessionStandardProps : ScopeOf<K> extends 'session-maybe' ? SessionMaybeStandardProps : object) & GlobalStandardProps;
339
+ /**
340
+ * One function-valued slot-level inject.hooks member. The factory is pure and
341
+ * returns the actual custom Hook; it must not invoke a Hook while being bound.
342
+ */
343
+ export type SlotHookFactory<K extends keyof SlotMap & string, Hook extends (...args: never[]) => unknown> = (standard: StandardPropsOf<K>, hookContext: HookContextOf<K>) => Hook;
344
+ /** Component-side Hook produced from one slot-level inject.hooks member. */
345
+ type BoundHookOf<Definition> = Definition extends HostObservable<infer Snapshot> ? SnapshotSelectorHook<Snapshot> : Definition extends (...args: never[]) => infer Hook ? Hook extends (...args: never[]) => unknown ? Hook : never : never;
346
+ /**
347
+ * Selector-hook share synthesized from a hooks compartment: each source
348
+ * `name` becomes a `use<Name>` selector hook over its snapshot type.
349
+ */
350
+ export type PropsSlotHooks<HS extends object> = {
351
+ [N in keyof HS & string as `use${Capitalize<N>}`]: BoundHookOf<HS[N]>;
352
+ };
353
+ /** Component-side view of a slot dispatcher's common inject face. */
354
+ export type SlotInjectFace<I extends object> = I extends {
355
+ hooks: infer HS extends object;
356
+ } ? Omit<I, 'hooks'> & PropsSlotHooks<HS> : I;
357
+ /** Selector-hook share synthesized from an entry inject hooks compartment. */
358
+ export type PropsHooks<HS extends HooksSources> = {
359
+ [N in keyof HS & string as `use${Capitalize<N>}`]: SnapshotSelectorHook<HS[N] extends HostObservable<infer T> ? T : never>;
360
+ };
361
+ /** Selector-hook share synthesized from an entry inject keyed-hooks compartment. */
362
+ export type PropsKeyedHooks<HS extends KeyedHooksSources> = {
363
+ [N in keyof HS & string as `use${Capitalize<N>}`]: KeyedSnapshotSelectorHook<HS[N] extends (key: string) => HostObservable<infer T> | undefined ? T : never>;
364
+ };
365
+ /**
366
+ * The component-side view of an inject face: the reserved `hooks`
367
+ * compartment (when declared) arrives as bound `use<Name>` selector hooks;
368
+ * every other member passes through verbatim.
369
+ */
370
+ export type InjectFace<I extends object> = I extends {
371
+ hooks: infer HS extends HooksSources;
372
+ } ? I extends {
373
+ keyedHooks: infer KS extends KeyedHooksSources;
374
+ } ? Omit<I, 'hooks' | 'keyedHooks'> & PropsHooks<HS> & PropsKeyedHooks<KS> : Omit<I, 'hooks'> & PropsHooks<HS> : I extends {
375
+ keyedHooks: infer KS extends KeyedHooksSources;
376
+ } ? Omit<I, 'keyedHooks'> & PropsKeyedHooks<KS> : I;
377
+ /**
378
+ * The composed component props intersection: runtime share (SlotMap) +
379
+ * child-render share (children declaration) + store share (declared handle) +
380
+ * the registrant's injected business face (its hooks compartment bound, see
381
+ * {@link InjectFace}) + the locale `t` seat (declared namespace, see
382
+ * {@link PropsLocale}). Each share derives from its single source of truth;
383
+ * components reference this composition, never re-type it.
384
+ */
385
+ 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>;
386
+ /**
387
+ * Inject factory parameter list, derived from the registration's declaration:
388
+ * strict session slots receive a definite framework-resolved `sessionId`;
389
+ * session-maybe slots receive the current id or `undefined`; a declared store
390
+ * appends the baked `actions` (the same callbacks the component receives).
391
+ * Business data access happens through the apply closure's ctx — no binding
392
+ * object parameter exists.
393
+ */
394
+ 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>>] : []);
395
+ /**
396
+ * A list-entry display label: a plain string, or a thunk re-evaluated per
397
+ * read so registration-time text (nav rows, tabs) follows the active locale
398
+ * without re-registration. Owners resolve through {@link resolveSlotLabel}.
399
+ */
400
+ export type SlotLabel = string | (() => string);
401
+ /**
402
+ * Kind shape fields carried in register options (keyed dispatch key; list
403
+ * id/order/label; chain select/priority; non-chain priority = cell shadowing rank).
404
+ */
405
+ export type KindOptions<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K>, M = never> = SlotMap[K]['kind'] extends 'keyed' ? {
406
+ key: EntryKey;
407
+ /** Cell shadowing rank (ascending, default 0, lowest renders; same key + same priority throws — see {@link SlotCore.register}). */
408
+ priority?: number;
409
+ } : SlotMap[K]['kind'] extends 'list' ? {
410
+ id: string;
411
+ order?: number;
412
+ label?: SlotLabel;
413
+ /** Cell shadowing rank (ascending, default 0, lowest renders; same id + same priority throws — see {@link SlotCore.register}). */
414
+ priority?: number;
415
+ } : SlotMap[K]['kind'] extends 'chain' ? {
416
+ /** Routing selector, mandatory on chain entries; `M` (the component's `matched` prop) infers from its return. */
417
+ select: ChainSelect<SlotMap[K] extends {
418
+ owner: infer O extends object;
419
+ } ? O : object, M>;
420
+ /** Explicit chain position (ascending, default 0, lower tries first); ties keep registration = assembly order. */
421
+ priority?: number;
422
+ } : {
423
+ /**
424
+ * Cell shadowing rank (ascending, default 0, lowest renders; a
425
+ * same-priority second registration throws — see {@link SlotCore.register}).
426
+ */
427
+ priority?: number;
428
+ };
429
+ /**
430
+ * Compile-time presence check: an entry declaring children MUST consume
431
+ * `renderSlot` (or `renderSlotChain` when its only children are chain slots)
432
+ * — declaring is claiming; an entry that does not render its children should
433
+ * not declare them. Evaluates to an unsatisfiable intersection member naming
434
+ * the declared keys when violated.
435
+ */
436
+ type RendersCheck<C, D> = [
437
+ keyof D & keyof SlotMap & string
438
+ ] extends [never] ? unknown : C extends (props: infer P) => ReactNode ? ('renderSlot' extends keyof P ? unknown : 'renderSlotChain' extends keyof P ? unknown : {
439
+ 'children declared but the component consumes no renderSlot': keyof D & keyof SlotMap & string;
440
+ }) : unknown;
441
+ /** Common register options share (see {@link SlotCore.register} for semantics). */
442
+ type BaseOptions<K extends keyof SlotMap & string, EntryKey extends EntryKeyOf<K>, D extends ChildrenDecl, H, M = never, N = undefined> = {
443
+ /** Target slot key (the entry contributes INTO this slot). */
444
+ name: K;
445
+ /** Child-slot declaration + render authorization + runtime spec, in one table. */
446
+ children?: D;
447
+ /** Store seat: a shared handle (apply-constructed) or an exclusive factory (framework-called per entry x scope). */
448
+ store?: H;
449
+ /**
450
+ * Dictionary namespace of this entry's copy. Declaring it puts the
451
+ * framework-synthesized `t` seat (typed to the namespace's dictionary
452
+ * union) on the component props; rendering requires an installed locale
453
+ * face — fails loud otherwise.
454
+ */
455
+ locale?: N;
456
+ /** Registrant identity label for diagnostics (the runtime Service wrapper stamps the caller's fiber name). */
457
+ registrant?: string;
458
+ } & KindOptions<K, EntryKey, M>;
459
+ /**
460
+ * One stored registration, as recorded by the core and read by the render
461
+ * machinery (type-erased at this boundary; the registration contract already proved
462
+ * the shares against the component).
463
+ */
464
+ export interface StoredEntry {
465
+ component: unknown;
466
+ options: {
467
+ key?: string;
468
+ id?: string;
469
+ order?: number;
470
+ label?: SlotLabel;
471
+ priority?: number;
472
+ };
473
+ /** Chain routing selector (type-erased like `inject`; present exactly on chain-slot entries). */
474
+ select?: ((owner: never) => unknown) | undefined;
475
+ /** Registrant business face; positional params derive from the declaration (sessionId?, actions?). */
476
+ inject?: ((...args: never[]) => Record<string, unknown>) | undefined;
477
+ /** Child-slot declaration table (declaration + authorization + runtime spec in one). */
478
+ children?: Readonly<Record<string, SlotSpec<SlotEntryDef>>> | undefined;
479
+ /** Declared store seat (instance resolution and lifecycle live with the host machinery). */
480
+ store?: StoreDecl | undefined;
481
+ /** Declared dictionary namespace (the render machinery synthesizes the `t` seat from it). */
482
+ locale?: string | undefined;
483
+ /** Diagnostics label of who registered. */
484
+ registrant?: string | undefined;
485
+ }
486
+ /**
487
+ * Resolve a possibly-thunked list label at read time (thunks follow the
488
+ * active locale; owners projecting ledger rows call this instead of reading
489
+ * `options.label` raw).
490
+ * @param label - the stored label.
491
+ * @returns the display string, or undefined when the entry declared none.
492
+ */
493
+ export declare function resolveSlotLabel(label: SlotLabel | undefined): string | undefined;
494
+ /** JSON-safe live occupant returned by slot inspection. */
495
+ export interface LiveSlotOccupant {
496
+ /** Plugin or package that registered the entry, when known. */
497
+ registrant?: string;
498
+ /** Keyed-slot cell. */
499
+ key?: string;
500
+ /** List-slot cell. */
501
+ id?: string;
502
+ /** List display order. */
503
+ order?: number;
504
+ /** Shadowing or chain priority. */
505
+ priority: number;
506
+ /** Whether the renderer currently selects this entry. */
507
+ active: boolean;
508
+ }
509
+ /** JSON-safe live slot declaration tree. */
510
+ export interface LiveSlotNode {
511
+ /** Exact SlotMap key. */
512
+ name: string;
513
+ /** Slot cardinality. */
514
+ kind: SlotKind;
515
+ /** Runtime data scope. */
516
+ scope: SlotScope;
517
+ /** Diagnostic owner of this declaration. */
518
+ declaredBy?: string;
519
+ /** Current registrations in ledger order. */
520
+ occupants: LiveSlotOccupant[];
521
+ /** Slots declared by entries mounted in this slot. */
522
+ children: LiveSlotNode[];
523
+ }
524
+ /**
525
+ * Pure slot registry (no cordis; event emission and the renderer installation contract
526
+ * live in the runtime Service wrapper).
527
+ *
528
+ * The 'root' slot is the one a-priori declaration, seeded at construction
529
+ * (single/root, declared by the framework) — the render tree's root hole.
530
+ *
531
+ * Change propagation contract: versions bump and {@link SlotCore.onMutate}
532
+ * fires synchronously per mutation (registry state is consistent when they
533
+ * fire); {@link SlotCore.subscribeDeclaration} fires synchronously for each
534
+ * declaration lifetime boundary; {@link SlotCore.subscribe} notifications
535
+ * batch per microtask, so N same-tick mutations produce one notification per
536
+ * touched key. Entry crash reports ({@link SlotCore.reportEntryError}) ride
537
+ * the same mutation channel when they abdicate, then notify
538
+ * {@link SlotCore.onEntryError} synchronously.
539
+ */
540
+ export declare class SlotCore {
541
+ private records;
542
+ private mutateListeners;
543
+ /** Shared-handle scope ledger: handle → the scope it first mounted under + live mount count. */
544
+ private handleScopes;
545
+ private dirty;
546
+ private flushScheduled;
547
+ /**
548
+ * Entries retired by an abdicating crash report
549
+ * ({@link SlotCore.reportEntryError}): excluded from
550
+ * {@link SlotCore.entriesOfSlot} projections for the rest of their
551
+ * registration's life, while the registration itself stays on the ledger
552
+ * (disposal authority remains with the registrant).
553
+ */
554
+ private abdicated;
555
+ private entryErrorListeners;
556
+ constructor();
557
+ /**
558
+ * Contribute a component to a declared slot and (optionally) declare child
559
+ * slots, a store seat, and the registrant's business face.
560
+ *
561
+ * Load-time validation (misconfiguration fails loud; the render hot path
562
+ * re-checks nothing): registering into an undeclared slot throws; declaring
563
+ * an already-declared child key throws (one declarer per slot — the message
564
+ * names the first declarer); mounting one shared store handle under slots
565
+ * of different scopes throws. Kind constraints: keyed — missing `key`
566
+ * throws; list — missing `id` throws; chain — missing `select` throws (the
567
+ * selector is the entry's routing seat, see {@link ChainSelect}).
568
+ *
569
+ * Shadowing (single/keyed/list): entries sharing one cell (single — the
570
+ * slot itself; keyed — same `key`; list — same `id`) coexist at distinct
571
+ * priorities, sorted ascending with ties keeping registration order; the
572
+ * cell's lowest live entry renders ({@link SlotCore.entriesOfSlot}). A
573
+ * second registration at an occupied cell's exact priority (default 0)
574
+ * throws naming the occupant, so priority-less composition keeps the
575
+ * historical one-occupant-per-cell fail-loud.
576
+ *
577
+ * Lifecycle: the disposer removes the contribution AND collapses every
578
+ * declared child slot (child entries clear recursively; their stale
579
+ * disposers become no-ops) — one lifecycle axis, no dangling state.
580
+ *
581
+ * @param options - registration options: target `name`, `children`
582
+ * declaration table, `store` seat, `inject` business-face factory, kind
583
+ * shape fields (keyed `key`; list `id`/`order`/`label`).
584
+ * @param component - component honoring the four-share composed props
585
+ * contract ({@link ComposedProps}); checked at this call site.
586
+ * @returns disposer removing the registration and its declarations
587
+ * (idempotent; stale disposers after a cascade are no-ops).
588
+ */
589
+ 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> & {
590
+ inject?: undefined;
591
+ }, 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;
592
+ /**
593
+ * Inject-bearing overload: identical semantics to the overload above, plus
594
+ * the registrant's business face — `I` is inferred from the inject
595
+ * factory's return and joins the component's composed-props constraint
596
+ * (factory parameters derive from the declaration, {@link InjectParams}).
597
+ * @param options - registration options plus the `inject` business-face factory.
598
+ * @param component - component honoring the four-share composed props
599
+ * contract including the inject share `I`.
600
+ * @returns disposer removing the registration and its declarations.
601
+ */
602
+ 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> & {
603
+ inject: (...args: InjectParams<K, H>) => I;
604
+ }, 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;
605
+ /**
606
+ * Whether a previously obtained entry is still registered (the render
607
+ * machinery's stale-authorization probe: a retained renderSlot binding
608
+ * whose entry left the ledger must not render).
609
+ * @param entry - a previously read entry.
610
+ * @returns false once the entry's registration was disposed.
611
+ */
612
+ isLive(entry: StoredEntry): boolean;
613
+ /**
614
+ * Snapshot the registered entries for a key. Returns the cached array
615
+ * reference (stable between mutations — safe as a uSES getSnapshot source);
616
+ * empty for keys not (or no longer) declared, so renderers may probe ahead
617
+ * of plugin load order.
618
+ * @param key - slot key (dynamic: the render machinery holds keys as strings).
619
+ * @returns entries in registration (list: order) sequence.
620
+ */
621
+ entries(key: string): readonly StoredEntry[];
622
+ /**
623
+ * Project a key's entries to its shadowing winners: the first live
624
+ * (non-abdicated) entry of each cell in priority order — single: the slot
625
+ * is one cell; keyed: one cell per `key`; list: one cell per `id` (winners
626
+ * keep ledger sequence; list renderers still refine display by `order`).
627
+ * Chain keys return the raw entries unchanged: election consumes every
628
+ * entry, shadowing does not apply. The raw {@link SlotCore.entries} view
629
+ * stays the inspection surface. Builds a fresh array per call — a render
630
+ * body read, not a uSES getSnapshot source.
631
+ * @param key - slot key (dynamic: the render machinery holds keys as strings).
632
+ * @returns the winning entry per occupied cell (empty while undeclared).
633
+ */
634
+ entriesOfSlot(key: string): readonly StoredEntry[];
635
+ /**
636
+ * Look up a slot's declared spec, narrowed by the SlotMap key.
637
+ * @param key - SlotMap key.
638
+ * @returns the spec, or undefined while undeclared.
639
+ */
640
+ spec<K extends keyof SlotMap & string>(key: K): SlotSpec<SlotMap[K]> | undefined;
641
+ /**
642
+ * Dynamic-key escape hatch for spec lookup — renderers resolving keys they
643
+ * only hold as strings (generic dispatch) use this wide form; statically
644
+ * keyed callers use {@link SlotCore.spec}.
645
+ * @param key - candidate slot key.
646
+ * @returns the wide-typed spec, or undefined while undeclared.
647
+ */
648
+ specDynamic(key: string): SlotSpec<SlotEntryDef> | undefined;
649
+ /**
650
+ * Export the current declaration topology without components or executable hooks.
651
+ * @param root - exact Slot key to select; omitted returns every live root.
652
+ * @returns selected live Slot trees, or an empty array when `root` is unavailable.
653
+ */
654
+ snapshot(root?: string): LiveSlotNode[];
655
+ /**
656
+ * Read the declaration lifetime of a key. Entry additions and removals do
657
+ * not change it; declaration creation and collapse each advance it.
658
+ * @param key - slot key.
659
+ * @returns monotonic epoch (0 before the first declaration).
660
+ */
661
+ declarationEpoch(key: string): number;
662
+ /**
663
+ * Subscribe to registration changes for a key (microtask-batched).
664
+ * Subscribing ahead of declaration is allowed; the declaration notifies.
665
+ * @param key - slot key.
666
+ * @param fn - change callback.
667
+ * @returns unsubscribe.
668
+ */
669
+ subscribe(key: string, fn: () => void): () => void;
670
+ /**
671
+ * Subscribe to declaration lifetime boundaries for a key. Notifications
672
+ * are synchronous so declaration teardown finishes before a subsequent
673
+ * same-tick registration can observe stale resources. Ordinary entry
674
+ * mutations do not notify this surface. A children table commits every
675
+ * sibling declaration before its first notification.
676
+ * @param key - slot key.
677
+ * @param fn - declaration or collapse callback.
678
+ * @returns unsubscribe.
679
+ */
680
+ subscribeDeclaration(key: string, fn: () => void): () => void;
681
+ /**
682
+ * Monotonic version for a key, bumped synchronously per mutation so a
683
+ * uSES getSnapshot read is never stale when its batched notification lands.
684
+ * @param key - slot key.
685
+ * @returns current version (0 for untouched keys).
686
+ */
687
+ getVersion(key: string): number;
688
+ /**
689
+ * Hook every mutation (the runtime Service wrapper bridges this to ctx.emit).
690
+ * Fires synchronously per mutation, unbatched — event semantics need one
691
+ * emission per change.
692
+ * @param fn - called with the mutated key.
693
+ * @returns unsubscribe.
694
+ */
695
+ onMutate(fn: (key: string) => void): () => void;
696
+ /**
697
+ * Renderer crash report from an entry boundary. Always notifies
698
+ * {@link SlotCore.onEntryError} listeners; with `info.abdicate` set (the
699
+ * shadowing kinds — single/keyed/list) it first retires the entry from its
700
+ * cell, one-shot: the record's version bumps through the ordinary mutation
701
+ * channel so outlets re-project onto the cell's next survivor, and a
702
+ * repeat abdicating report no-ops entirely. Chain crashes report with
703
+ * `abdicate: false` — election alternatives resolve at select time, so the
704
+ * entry keeps its cell and only the notification fires. The registration
705
+ * itself stays on the ledger either way — raw {@link SlotCore.entries}
706
+ * still lists the entry and its disposer keeps working.
707
+ * @param key - slot key the entry rendered under.
708
+ * @param entry - the crashed entry.
709
+ * @param error - the crash cause, forwarded to listeners verbatim.
710
+ * @param info - `abdicate`: whether the crash retires the entry from its cell.
711
+ */
712
+ reportEntryError(key: string, entry: StoredEntry, error: unknown, info: {
713
+ abdicate: boolean;
714
+ }): void;
715
+ /**
716
+ * Observe entry boundary crashes (every render-time entry failure the
717
+ * boundaries contain, abdicating or not) — the supervision seam for hosts
718
+ * mirroring contribution health. Fires synchronously per report, after the
719
+ * registry mutated for abdicating crashes (same listener discipline as
720
+ * {@link SlotCore.onMutate}).
721
+ * @param fn - called with the slot key, the crashed entry, the crash
722
+ * cause, and `abdicated`: whether the crash retired the entry from its cell.
723
+ * @returns unsubscribe.
724
+ */
725
+ onEntryError(fn: (key: string, entry: StoredEntry, error: unknown, info: {
726
+ abdicated: boolean;
727
+ }) => void): () => void;
728
+ /**
729
+ * Cascade for a removed entry: release its store mount and collapse every
730
+ * child slot it declared — specs clear, contributions empty (their stale
731
+ * disposers no-op), recursively down the declaration tree. One lifecycle
732
+ * axis: ledger rows, slots, contributions, and store mounts die together.
733
+ */
734
+ private releaseEntry;
735
+ private record;
736
+ private markDirty;
737
+ private notifyDeclaration;
738
+ private flush;
739
+ }
740
+ //# sourceMappingURL=index.d.ts.map