@x1a0f3n9/dsh-client-ui-renderer 0.1.5-rc.5 → 0.1.7-rc.3
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.
- package/README.i18n.yaml +51 -5
- package/README.md +4 -3
- package/README.zh.md +4 -3
- package/lib/client.js +467 -59
- package/lib/types/client/bindings.d.ts +13 -5
- package/lib/types/client/errors.d.ts +5 -0
- package/lib/types/client/index.d.ts +2 -1
- package/lib/types/client/registry.d.ts +36 -25
- package/package.json +6 -6
package/README.i18n.yaml
CHANGED
|
@@ -1,6 +1,52 @@
|
|
|
1
|
-
# Bilingual-pair consistency record (docs/i18n/README.md):
|
|
2
|
-
#
|
|
3
|
-
#
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-renderer/README.md
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/:
|
|
6
|
+
en: 06bd9d926c743736
|
|
7
|
+
zh: 39acdcb577fd8c6d
|
|
8
|
+
/x1a0f3n9-dsh-client-ui-renderer:
|
|
9
|
+
en: 3569f2670b8a1fce
|
|
10
|
+
zh: 5bbedcc4e539d186
|
|
11
|
+
/x1a0f3n9-dsh-client-ui-renderer/summary:
|
|
12
|
+
en: cae0bce110641caf
|
|
13
|
+
zh: e5bde9dba75389bc
|
|
14
|
+
/x1a0f3n9-dsh-client-ui-renderer/table-of-contents:
|
|
15
|
+
en: d152484eb41ac6b4
|
|
16
|
+
zh: 09388d293f9be9cb
|
|
17
|
+
/x1a0f3n9-dsh-client-ui-renderer/use-this-package:
|
|
18
|
+
en: 4873b12ddeac04f2
|
|
19
|
+
zh: 027845407b207c4f
|
|
20
|
+
/x1a0f3n9-dsh-client-ui-renderer/use-this-package/what-mounting-does:
|
|
21
|
+
en: 16f8f781e259f0ee
|
|
22
|
+
zh: aa2b4783807fe943
|
|
23
|
+
/x1a0f3n9-dsh-client-ui-renderer/use-this-package/for-business-plugins:
|
|
24
|
+
en: 15a2bfee2c0bd051
|
|
25
|
+
zh: 0c5b336fc5afbbc6
|
|
26
|
+
/x1a0f3n9-dsh-client-ui-renderer/understand-the-implementation:
|
|
27
|
+
en: 0de0a8ad857b93f6
|
|
28
|
+
zh: 98a0fae2d6606a7d
|
|
29
|
+
/x1a0f3n9-dsh-client-ui-renderer/understand-the-implementation/activation-and-mount:
|
|
30
|
+
en: 822adba4ecd1b7e3
|
|
31
|
+
zh: bab3626fbe30ff55
|
|
32
|
+
/x1a0f3n9-dsh-client-ui-renderer/understand-the-implementation/slot-bindings:
|
|
33
|
+
en: 6ab26cf5744a23d4
|
|
34
|
+
zh: 84a531322a724a84
|
|
35
|
+
/x1a0f3n9-dsh-client-ui-renderer/understand-the-implementation/identity:
|
|
36
|
+
en: 2a349d500ead79cb
|
|
37
|
+
zh: ac49c8b1d73dcd6c
|
|
38
|
+
/x1a0f3n9-dsh-client-ui-renderer/further-exploration:
|
|
39
|
+
en: 77b43b2f3d55c933
|
|
40
|
+
zh: 9847b53486372aeb
|
|
41
|
+
/x1a0f3n9-dsh-client-ui-renderer/model-experience:
|
|
42
|
+
en: ca4e29db08d34e6d
|
|
43
|
+
zh: de6ec680414b1d54
|
|
44
|
+
/x1a0f3n9-dsh-client-ui-renderer/model-experience/kv-cache-effect:
|
|
45
|
+
en: ca75c51c89c2c9b0
|
|
46
|
+
zh: de54f3467ef3b9be
|
|
47
|
+
/x1a0f3n9-dsh-client-ui-renderer/known-limitations-and-deferred-work:
|
|
48
|
+
en: 686023788b76788f
|
|
49
|
+
zh: 2bb3ca909746c485
|
|
50
|
+
/x1a0f3n9-dsh-client-ui-renderer/known-limitations-and-deferred-work/dev-note:
|
|
51
|
+
en: e67f633dc6fe7773
|
|
52
|
+
zh: 3bb0c20c93f16f98
|
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Browser UI renderer: React
|
|
2
|
+
description: "Browser UI renderer: React bindings for ordinary Slots and reusable Component Factories, ctx.uiRenderer, and the assembled dsh web application root."
|
|
3
3
|
kind: "package-reference"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -33,7 +33,7 @@ This package is infrastructure: the web shell and the boot kernel are its only d
|
|
|
33
33
|
|
|
34
34
|
### For business plugins
|
|
35
35
|
|
|
36
|
-
A business plugin registers
|
|
36
|
+
A business plugin registers an ordinary Slot entry or a reusable Component Factory; the renderer binds the runtime's session and workspace observable sources into selector hooks at the render position. The plugin receives standard scope props through its derived Component props — it never imports the renderer or touches React internals. Every renderer-created Component can render a Factory occurrence, and a Factory can expose caller-selected local Components without sharing implementation values between packages.
|
|
37
37
|
|
|
38
38
|
-----
|
|
39
39
|
|
|
@@ -51,7 +51,7 @@ The plugin installs `createSlotRenderer()` and reflects the `uiRenderer` service
|
|
|
51
51
|
|
|
52
52
|
### Slot bindings
|
|
53
53
|
|
|
54
|
-
`createSlotRenderer` connects the slot registry to React: entry lists become reactive sources, and each outlet renders through the installed renderer. Business plugins pass bare observable sources through typed
|
|
54
|
+
`createSlotRenderer` connects the slot registry to React: ordinary entry lists and Factory definitions become reactive sources, and each outlet or occurrence renders through the installed renderer. Business plugins pass bare observable sources through typed `hooks`; the renderer binds them at the render position via the uSES adapter. A Factory Store factory stays lazy until an occurrence first materializes; its exclusive handle rejects persistence, render-time records stay weak, and an idempotent effect strongly retains only mounted occurrences while preserving identity across effect replay. Factory errors use the ordinary supervision channel without abdicating the shared definition: the definition and its fallback local Components report against the definition, caller-selected local Components report against the caller registration, and each boundary resets with its own scope incarnation.
|
|
55
55
|
|
|
56
56
|
### Identity
|
|
57
57
|
|
|
@@ -71,6 +71,7 @@ These pages cover the surrounding machinery and the composition model.
|
|
|
71
71
|
- [ui-session](../ui-session/README.md) — the adapter that supplies the standard Session sources and hooks this renderer binds.
|
|
72
72
|
- [Web client architecture](../../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md) — the loading chain, object layer, and layering red lines.
|
|
73
73
|
- [Slot system standard](../../../.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.md) — the definitive composition model.
|
|
74
|
+
- [Component Factories](../../../.agents/notes/implemented/architecture/2026-09-10-component-factories-and-local-slots.md) — reusable definitions, local Component selection, and occurrence lifetimes.
|
|
74
75
|
|
|
75
76
|
-----
|
|
76
77
|
|
package/README.zh.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "浏览器 UI
|
|
2
|
+
description: "浏览器 UI 渲染器:普通 Slot 与可复用 Component Factory 的 React 绑定、ctx.uiRenderer 与组装后的 dsh Web 应用根。"
|
|
3
3
|
kind: "package-reference"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -33,7 +33,7 @@ kind: "package-reference"
|
|
|
33
33
|
|
|
34
34
|
### 对业务插件
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
业务插件注册普通 Slot entry 或可复用 Component Factory;渲染器在渲染位置把运行时的会话与 Workspace observable source 绑定为 selector 钩子。插件通过推导出的 Component props 收到标准 scope props——它绝不导入渲染器,也不触碰 React 内部机制。每个由 renderer 创建的 Component 都能渲染 Factory occurrence,Factory 也能暴露由调用方选择的局部 Component,而无需在包之间共享实现值。
|
|
37
37
|
|
|
38
38
|
-----
|
|
39
39
|
|
|
@@ -51,7 +51,7 @@ kind: "package-reference"
|
|
|
51
51
|
|
|
52
52
|
### Slot 绑定
|
|
53
53
|
|
|
54
|
-
`createSlotRenderer` 把 slot 注册表连接到 React
|
|
54
|
+
`createSlotRenderer` 把 slot 注册表连接到 React:普通 entry list 与 Factory definition 成为响应式 source,每个 outlet 或 occurrence 经已安装的渲染器渲染。业务插件通过带类型的 `hooks` 传递裸 observable source;渲染器经 uSES 适配器在渲染位置完成绑定。Factory Store factory 保持 lazy,直到 occurrence 首次物化时才创建 handle;其 exclusive handle 拒绝持久化,渲染期记录保持弱引用,幂等 effect 仅强引用 mounted occurrences,同时在 effect replay 期间保留 identity。Factory 错误使用普通监督通道且不会 abdicate 共享 definition:definition 及其 fallback 局部 Component 的失败归属 definition,调用方所选局部 Component 的失败归属调用方 registration,每个边界随自身 scope incarnation 重置。
|
|
55
55
|
|
|
56
56
|
### 身份
|
|
57
57
|
|
|
@@ -71,6 +71,7 @@ React、React DOM、Cordis、ui-slots 与 ui-primitives 通过 Web 外壳的静
|
|
|
71
71
|
- [ui-session](../ui-session/README.zh.md)——提供本渲染器所绑定标准会话 source 与钩子的适配器。
|
|
72
72
|
- [Web 客户端架构](../../../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.zh.md)——加载链、对象层与分层红线。
|
|
73
73
|
- [slot 系统标准](../../../.agents/notes/implemented/architecture/2026-07-22-slot-type-chain-implementation.zh.md)——权威组合模型。
|
|
74
|
+
- [Component Factory](../../../.agents/notes/implemented/architecture/2026-09-10-component-factories-and-local-slots.zh.md)——可复用 definitions、局部 Component 选择与 occurrence 生命周期。
|
|
74
75
|
|
|
75
76
|
-----
|
|
76
77
|
|
package/lib/client.js
CHANGED
|
@@ -160,10 +160,13 @@ window.__ModuleLoader__.load({
|
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
162
|
//#endregion
|
|
163
|
+
//#region lib/types/client/errors.js
|
|
164
|
+
/** Shared renderer failure categories. @module */
|
|
165
|
+
/** Renderer assembly failures that must escape component error boundaries. */
|
|
166
|
+
var SlotAssemblyError = class extends Error {};
|
|
167
|
+
//#endregion
|
|
163
168
|
//#region lib/types/client/bindings.js
|
|
164
169
|
/** Internal React bindings for renderer hosts and standard-source scopes. */
|
|
165
|
-
/** Missing renderer assembly dependency. */
|
|
166
|
-
var SlotAssemblyError = class extends Error {};
|
|
167
170
|
/** In-package renderer host context. */
|
|
168
171
|
const HostContext = (0, react.createContext)(null);
|
|
169
172
|
/**
|
|
@@ -196,6 +199,19 @@ window.__ModuleLoader__.load({
|
|
|
196
199
|
return binding;
|
|
197
200
|
}
|
|
198
201
|
/**
|
|
202
|
+
* Publish one resolved scope binding to a renderer subtree.
|
|
203
|
+
* @param props - provider inputs.
|
|
204
|
+
* @param props.binding - binding exposed to scoped entries.
|
|
205
|
+
* @param props.children - subtree that inherits the binding.
|
|
206
|
+
* @returns the scoped React provider.
|
|
207
|
+
*/
|
|
208
|
+
function ScopeBindingProvider({ binding, children }) {
|
|
209
|
+
return (0, react_jsx_runtime.jsx)(ScopeBindingContext.Provider, {
|
|
210
|
+
value: binding,
|
|
211
|
+
children
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
199
215
|
* Bind one observable source to an identity-stable selector Hook.
|
|
200
216
|
* @param source - observable source.
|
|
201
217
|
* @returns cached selector Hook.
|
|
@@ -230,20 +246,36 @@ window.__ModuleLoader__.load({
|
|
|
230
246
|
* @param source - keyed resolver, or absence for an optional scope.
|
|
231
247
|
* @returns cached keyed selector Hook.
|
|
232
248
|
*/
|
|
233
|
-
function keyedObservableHook(source) {
|
|
249
|
+
function keyedObservableHook(source, defaultKey) {
|
|
234
250
|
if (source === void 0) return absentKeyedHook;
|
|
235
|
-
let
|
|
251
|
+
let hooks = keyedHookCache.get(source);
|
|
252
|
+
if (hooks === void 0) {
|
|
253
|
+
hooks = /* @__PURE__ */ new Map();
|
|
254
|
+
keyedHookCache.set(source, hooks);
|
|
255
|
+
}
|
|
256
|
+
const cacheKey = defaultKey ?? NO_DEFAULT_KEY;
|
|
257
|
+
let hook = hooks.get(cacheKey);
|
|
236
258
|
if (hook === void 0) {
|
|
237
|
-
hook = (
|
|
238
|
-
|
|
259
|
+
hook = (keyOrSelector, selectorOrEqual, equal) => {
|
|
260
|
+
const keyed = typeof keyOrSelector === "string";
|
|
261
|
+
const key = keyed ? keyOrSelector : defaultKey;
|
|
262
|
+
const selector = keyed ? selectorOrEqual : keyOrSelector;
|
|
263
|
+
const comparison = keyed ? equal : selectorOrEqual;
|
|
264
|
+
return observableHook(key === void 0 ? absentSource : source(key) ?? absentSource)(selector ?? identity, comparison);
|
|
239
265
|
};
|
|
240
|
-
|
|
266
|
+
hooks.set(cacheKey, hook);
|
|
241
267
|
}
|
|
242
268
|
return hook;
|
|
243
269
|
}
|
|
270
|
+
const NO_DEFAULT_KEY = Symbol("no default key");
|
|
244
271
|
const keyedHookCache = /* @__PURE__ */ new WeakMap();
|
|
245
272
|
const identity = (value) => value;
|
|
246
|
-
const absentKeyedHook = (
|
|
273
|
+
const absentKeyedHook = (keyOrSelector, selectorOrEqual, equal) => {
|
|
274
|
+
const keyed = typeof keyOrSelector === "string";
|
|
275
|
+
const selector = keyed ? selectorOrEqual : keyOrSelector;
|
|
276
|
+
const comparison = keyed ? equal : selectorOrEqual;
|
|
277
|
+
return observableHook(absentSource)(selector ?? identity, comparison);
|
|
278
|
+
};
|
|
247
279
|
/** Subscribe the tree to the atomically assembled root standard-source roster. */
|
|
248
280
|
function RootStandardProvider({ children }) {
|
|
249
281
|
const binding = observableHook(useHost().root)((value) => value);
|
|
@@ -270,6 +302,20 @@ window.__ModuleLoader__.load({
|
|
|
270
302
|
* React renderer for declarative slots. Per-entry bindings enforce child
|
|
271
303
|
* authorization, and entry boundaries contain registrant failures.
|
|
272
304
|
*/
|
|
305
|
+
const factoryRenderCache = /* @__PURE__ */ new WeakMap();
|
|
306
|
+
function boundRenderFactorySlot(caller) {
|
|
307
|
+
let render = factoryRenderCache.get(caller);
|
|
308
|
+
if (render !== void 0) return render;
|
|
309
|
+
render = ((name, props, options) => (0, react_jsx_runtime.jsx)(FactoryOutlet, {
|
|
310
|
+
name,
|
|
311
|
+
inputProps: props,
|
|
312
|
+
slots: options?.slots,
|
|
313
|
+
fallback: options?.fallback,
|
|
314
|
+
caller
|
|
315
|
+
}));
|
|
316
|
+
factoryRenderCache.set(caller, render);
|
|
317
|
+
return render;
|
|
318
|
+
}
|
|
273
319
|
/**
|
|
274
320
|
* Per-entry renderSlot bindings. The binding is identity-stable per entry
|
|
275
321
|
* (memoized components must not resubscribe on unrelated re-renders) and dies
|
|
@@ -320,6 +366,42 @@ window.__ModuleLoader__.load({
|
|
|
320
366
|
}
|
|
321
367
|
return binding;
|
|
322
368
|
}
|
|
369
|
+
const factoryRenderSlotCache = /* @__PURE__ */ new WeakMap();
|
|
370
|
+
const factoryRenderSlotChainCache = /* @__PURE__ */ new WeakMap();
|
|
371
|
+
function boundFactoryRenderSlot(host, definition) {
|
|
372
|
+
let binding = factoryRenderSlotCache.get(definition);
|
|
373
|
+
if (binding !== void 0) return binding;
|
|
374
|
+
binding = (key, owner, opts) => {
|
|
375
|
+
if (!host.isFactoryLive(definition)) throw new _x1a0f3n9_dsh_client_ui_slots.StaleAuthorizationError(`renderSlot('${key}') from a disposed Factory`);
|
|
376
|
+
const declared = definition.children?.[key];
|
|
377
|
+
if (declared === void 0) throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`slot '${key}' is not declared by this Factory`);
|
|
378
|
+
if (declared.kind === "chain") throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`slot '${key}' is declared 'chain' — use renderSlotChain`);
|
|
379
|
+
return (0, react_jsx_runtime.jsx)(SlotOutlet, {
|
|
380
|
+
slotKey: key,
|
|
381
|
+
ownerProps: owner,
|
|
382
|
+
opts
|
|
383
|
+
});
|
|
384
|
+
};
|
|
385
|
+
factoryRenderSlotCache.set(definition, binding);
|
|
386
|
+
return binding;
|
|
387
|
+
}
|
|
388
|
+
function boundFactoryRenderSlotChain(host, definition) {
|
|
389
|
+
let binding = factoryRenderSlotChainCache.get(definition);
|
|
390
|
+
if (binding !== void 0) return binding;
|
|
391
|
+
binding = (key, owner, opts) => {
|
|
392
|
+
if (!host.isFactoryLive(definition)) throw new _x1a0f3n9_dsh_client_ui_slots.StaleAuthorizationError(`renderSlotChain('${key}') from a disposed Factory`);
|
|
393
|
+
const declared = definition.children?.[key];
|
|
394
|
+
if (declared === void 0) throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`slot '${key}' is not declared by this Factory`);
|
|
395
|
+
if (declared.kind !== "chain") throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`slot '${key}' is declared '${declared.kind}', not 'chain' — use renderSlot`);
|
|
396
|
+
return (0, react_jsx_runtime.jsx)(SlotOutlet, {
|
|
397
|
+
slotKey: key,
|
|
398
|
+
ownerProps: owner,
|
|
399
|
+
opts
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
factoryRenderSlotChainCache.set(definition, binding);
|
|
403
|
+
return binding;
|
|
404
|
+
}
|
|
323
405
|
/**
|
|
324
406
|
* Inject results cache: root entries per entry, session entries per
|
|
325
407
|
* (entry x scope binding). WeakMap keys are entry/binding objects (both
|
|
@@ -506,6 +588,16 @@ window.__ModuleLoader__.load({
|
|
|
506
588
|
}
|
|
507
589
|
return key;
|
|
508
590
|
}
|
|
591
|
+
let nextSessionGenerationKey = 0;
|
|
592
|
+
const sessionGenerationKeys = /* @__PURE__ */ new WeakMap();
|
|
593
|
+
function sessionGenerationKeyOf(binding) {
|
|
594
|
+
let key = sessionGenerationKeys.get(binding.ctx);
|
|
595
|
+
if (key === void 0) {
|
|
596
|
+
key = nextSessionGenerationKey++;
|
|
597
|
+
sessionGenerationKeys.set(binding.ctx, key);
|
|
598
|
+
}
|
|
599
|
+
return key;
|
|
600
|
+
}
|
|
509
601
|
/**
|
|
510
602
|
* Per-entry isolation: one registrant crashing (component render or inject
|
|
511
603
|
* factory) must not take down siblings. Assembly errors (missing providers)
|
|
@@ -531,11 +623,27 @@ window.__ModuleLoader__.load({
|
|
|
531
623
|
return this.props.children;
|
|
532
624
|
}
|
|
533
625
|
};
|
|
626
|
+
/** Contain one Factory occurrence without retiring the shared definition. */
|
|
627
|
+
var FactoryErrorBoundary = class extends react.Component {
|
|
628
|
+
state = { failed: false };
|
|
629
|
+
static getDerivedStateFromError(error) {
|
|
630
|
+
if (error instanceof SlotAssemblyError) throw error;
|
|
631
|
+
return { failed: true };
|
|
632
|
+
}
|
|
633
|
+
componentDidCatch(error) {
|
|
634
|
+
console.error(`slot factory occurrence crashed in '${this.props.name}':`, error);
|
|
635
|
+
this.props.onEntryError(error);
|
|
636
|
+
}
|
|
637
|
+
render() {
|
|
638
|
+
if (this.state.failed) return (0, react_jsx_runtime.jsx)("div", { "data-factory-error": this.props.name });
|
|
639
|
+
return this.props.children;
|
|
640
|
+
}
|
|
641
|
+
};
|
|
534
642
|
const rootStandardCache = /* @__PURE__ */ new WeakMap();
|
|
535
643
|
const sessionStandardCache = /* @__PURE__ */ new WeakMap();
|
|
536
644
|
const sessionMaybeStandardCache = /* @__PURE__ */ new WeakMap();
|
|
537
645
|
/** Materialize one binding into stable framework Hook and plain-prop seats. */
|
|
538
|
-
function materializeStandardBinding(binding, optional) {
|
|
646
|
+
function materializeStandardBinding(binding, optional, defaultKey) {
|
|
539
647
|
const standard = { ...binding.props };
|
|
540
648
|
for (const [name, source] of Object.entries(binding.hooks)) {
|
|
541
649
|
if (source === void 0 && !optional) throw new SlotAssemblyError(`strict standard hook '${name}' has no source`);
|
|
@@ -543,7 +651,7 @@ window.__ModuleLoader__.load({
|
|
|
543
651
|
}
|
|
544
652
|
for (const [name, source] of Object.entries(binding.keyedHooks)) {
|
|
545
653
|
if (source === void 0 && !optional) throw new SlotAssemblyError(`strict keyed standard hook '${name}' has no source resolver`);
|
|
546
|
-
standard[(0, _x1a0f3n9_dsh_client_ui_slots.standardHookPropName)(name)] = keyedObservableHook(source);
|
|
654
|
+
standard[(0, _x1a0f3n9_dsh_client_ui_slots.standardHookPropName)(name)] = keyedObservableHook(source, defaultKey);
|
|
547
655
|
}
|
|
548
656
|
return standard;
|
|
549
657
|
}
|
|
@@ -565,7 +673,7 @@ window.__ModuleLoader__.load({
|
|
|
565
673
|
let standard = perScope.get(scopeBinding);
|
|
566
674
|
if (standard !== void 0) return standard;
|
|
567
675
|
standard = {
|
|
568
|
-
...
|
|
676
|
+
...materializeStandardBinding(rootBinding, false, scopeBinding.key),
|
|
569
677
|
...materializeStandardBinding(scopeBinding, scope === "session-maybe")
|
|
570
678
|
};
|
|
571
679
|
perScope.set(scopeBinding, standard);
|
|
@@ -579,7 +687,15 @@ window.__ModuleLoader__.load({
|
|
|
579
687
|
if (adapter.renderArea === void 0) throw new SlotAssemblyError("scope 'session' adapter does not provide its area renderer");
|
|
580
688
|
const renderArea = adapter.renderArea.bind(adapter);
|
|
581
689
|
Provider = function ScopeAreaProvider(props) {
|
|
582
|
-
|
|
690
|
+
const inherited = useScopeBinding();
|
|
691
|
+
const explicit = Object.hasOwn(props, "session");
|
|
692
|
+
const source = adapter.bindingSource(props.session);
|
|
693
|
+
const resolved = (0, react.useSyncExternalStore)((listener) => source.subscribe(listener), () => source.getSnapshot(), () => source.getSnapshot());
|
|
694
|
+
const binding = explicit ? resolved : inherited;
|
|
695
|
+
return (0, react_jsx_runtime.jsx)(ScopeBindingProvider, {
|
|
696
|
+
binding,
|
|
697
|
+
children: renderArea(binding, props)
|
|
698
|
+
});
|
|
583
699
|
};
|
|
584
700
|
scopeAreaCache.set(adapter, Provider);
|
|
585
701
|
return Provider;
|
|
@@ -598,7 +714,10 @@ window.__ModuleLoader__.load({
|
|
|
598
714
|
*/
|
|
599
715
|
function standardKit(host, entry, scope, rootBinding, scopeBinding) {
|
|
600
716
|
const standard = standardProps(scope, rootBinding, scopeBinding);
|
|
601
|
-
const kit = {
|
|
717
|
+
const kit = {
|
|
718
|
+
...standard,
|
|
719
|
+
renderFactorySlot: boundRenderFactorySlot(entry)
|
|
720
|
+
};
|
|
602
721
|
if (entry.locale !== void 0) {
|
|
603
722
|
const face = host.locale;
|
|
604
723
|
if (face === void 0) throw new SlotAssemblyError(`entry declares locale namespace '${entry.locale}' but no locale face is installed (locale plugin missing from the composition?)`);
|
|
@@ -613,7 +732,7 @@ window.__ModuleLoader__.load({
|
|
|
613
732
|
if (entry.children !== void 0) {
|
|
614
733
|
kit["renderSlot"] = boundRenderSlot(host, entry);
|
|
615
734
|
if (Object.values(entry.children).some((spec) => spec.kind === "chain")) kit["renderSlotChain"] = boundRenderSlotChain(host, entry);
|
|
616
|
-
if (Object.values(entry.children).some((spec) => spec.scope
|
|
735
|
+
if (Object.values(entry.children).some((spec) => spec.scope !== "root")) {
|
|
617
736
|
const adapter = host.scope("session");
|
|
618
737
|
if (adapter === void 0) throw new SlotAssemblyError("entry declares a session child without an installed 'session' scope adapter");
|
|
619
738
|
kit["SessionProvider"] = scopeAreaProvider(adapter);
|
|
@@ -697,22 +816,39 @@ window.__ModuleLoader__.load({
|
|
|
697
816
|
*/
|
|
698
817
|
function SessionMaybeEntry({ entry, ownerProps, slotKey, slotInjected, hookContext, hasHookContext }) {
|
|
699
818
|
const binding = useScopeBinding();
|
|
819
|
+
const epoch = useMaybeIncarnation(binding);
|
|
820
|
+
return (0, react_jsx_runtime.jsx)(SessionMaybeEntryBody, {
|
|
821
|
+
entry,
|
|
822
|
+
ownerProps,
|
|
823
|
+
binding,
|
|
824
|
+
slotKey,
|
|
825
|
+
slotInjected,
|
|
826
|
+
hookContext,
|
|
827
|
+
hasHookContext
|
|
828
|
+
}, epoch);
|
|
829
|
+
}
|
|
830
|
+
const FIRST_INCARNATION = {
|
|
831
|
+
adopted: void 0,
|
|
832
|
+
epoch: 0
|
|
833
|
+
};
|
|
834
|
+
function useMaybeIncarnation(binding) {
|
|
835
|
+
const identity = binding.key === void 0 ? void 0 : binding.ctx;
|
|
700
836
|
const [state, setState] = (0, react.useState)(FIRST_INCARNATION);
|
|
701
837
|
let { adopted, epoch } = state;
|
|
702
|
-
if (
|
|
703
|
-
adopted =
|
|
838
|
+
if (identity !== void 0 && adopted === void 0) {
|
|
839
|
+
adopted = identity;
|
|
704
840
|
setState({
|
|
705
841
|
adopted,
|
|
706
842
|
epoch
|
|
707
843
|
});
|
|
708
|
-
} else if (adopted !== void 0 &&
|
|
709
|
-
adopted =
|
|
844
|
+
} else if (adopted !== void 0 && identity !== void 0 && identity !== adopted) {
|
|
845
|
+
adopted = identity;
|
|
710
846
|
epoch += 1;
|
|
711
847
|
setState({
|
|
712
848
|
adopted,
|
|
713
849
|
epoch
|
|
714
850
|
});
|
|
715
|
-
} else if (adopted !== void 0 &&
|
|
851
|
+
} else if (adopted !== void 0 && identity === void 0) {
|
|
716
852
|
adopted = void 0;
|
|
717
853
|
epoch += 1;
|
|
718
854
|
setState({
|
|
@@ -720,20 +856,8 @@ window.__ModuleLoader__.load({
|
|
|
720
856
|
epoch
|
|
721
857
|
});
|
|
722
858
|
}
|
|
723
|
-
return
|
|
724
|
-
entry,
|
|
725
|
-
ownerProps,
|
|
726
|
-
binding,
|
|
727
|
-
slotKey,
|
|
728
|
-
slotInjected,
|
|
729
|
-
hookContext,
|
|
730
|
-
hasHookContext
|
|
731
|
-
}, epoch);
|
|
859
|
+
return epoch;
|
|
732
860
|
}
|
|
733
|
-
const FIRST_INCARNATION = {
|
|
734
|
-
adopted: void 0,
|
|
735
|
-
epoch: 0
|
|
736
|
-
};
|
|
737
861
|
function RootEntry({ entry, ownerProps, slotKey, slotInjected, hookContext, hasHookContext }) {
|
|
738
862
|
const host = useHost();
|
|
739
863
|
const rootBinding = useRootBinding();
|
|
@@ -741,22 +865,225 @@ window.__ModuleLoader__.load({
|
|
|
741
865
|
const { kit, standard, actions } = standardKit(host, entry, "root", rootBinding, void 0);
|
|
742
866
|
return renderEntry(slotKey, Comp, kit, standard, cachedRootInject(entry, actions), slotInjected, ownerProps, hookContext, hasHookContext);
|
|
743
867
|
}
|
|
868
|
+
const FactoryOccurrenceContext = (0, react.createContext)(null);
|
|
869
|
+
const FactoryAncestryContext = (0, react.createContext)(/* @__PURE__ */ new Set());
|
|
870
|
+
const EMPTY_FACTORY_SELECTION = {};
|
|
871
|
+
function useFactorySlotRuntime(name, fallback) {
|
|
872
|
+
const occurrence = (0, react.useContext)(FactoryOccurrenceContext);
|
|
873
|
+
if (occurrence === null) throw new SlotAssemblyError("useFactorySlot() called outside a Factory occurrence");
|
|
874
|
+
if (!occurrence.host.isFactoryLive(occurrence.definition)) throw new _x1a0f3n9_dsh_client_ui_slots.StaleAuthorizationError(`useFactorySlot('${name}') from a disposed Factory`);
|
|
875
|
+
const declared = occurrence.definition.slots?.[name];
|
|
876
|
+
if (declared === void 0) throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`local slot '${name}' is not declared by factory '${occurrence.definition.name}'`);
|
|
877
|
+
const selected = occurrence.selected[name];
|
|
878
|
+
const Selected = selected ?? fallback;
|
|
879
|
+
const usesFallback = selected === void 0;
|
|
880
|
+
const { definition, host } = occurrence;
|
|
881
|
+
return (0, react.useMemo)(function bindFactoryLocalComponent() {
|
|
882
|
+
return function BoundFactoryLocalComponent(localProps) {
|
|
883
|
+
const current = (0, react.useContext)(FactoryOccurrenceContext);
|
|
884
|
+
const localScopeBinding = useScopeBinding();
|
|
885
|
+
const localMaybeEpoch = useMaybeIncarnation(localScopeBinding);
|
|
886
|
+
if (!host.isFactoryLive(definition)) throw new _x1a0f3n9_dsh_client_ui_slots.StaleAuthorizationError(`local slot '${name}' from a disposed Factory`);
|
|
887
|
+
if (current === null || current.definition !== definition) throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`local slot '${name}' rendered outside factory '${definition.name}'`);
|
|
888
|
+
if (declared.scope === "session" && localScopeBinding.key === void 0) throw new SlotAssemblyError(`strict session local slot '${name}' from factory '${definition.name}' rendered without a scope binding`);
|
|
889
|
+
const localOwner = usesFallback ? definition : current.caller;
|
|
890
|
+
const localScopeIdentity = declared.scope === "root" ? "root" : declared.scope === "session" ? `session:${sessionGenerationKeyOf(localScopeBinding)}` : `session-maybe:${localMaybeEpoch}`;
|
|
891
|
+
const localStandard = standardProps(declared.scope, current.rootBinding, localScopeBinding);
|
|
892
|
+
const localRegistrationKit = {
|
|
893
|
+
...current.registrationKit,
|
|
894
|
+
renderFactorySlot: boundRenderFactorySlot(localOwner)
|
|
895
|
+
};
|
|
896
|
+
assertNoPropOverlap(`factory '${definition.name}' local slot '${name}'`, localRegistrationKit, localStandard);
|
|
897
|
+
const provided = {
|
|
898
|
+
...localRegistrationKit,
|
|
899
|
+
...localStandard
|
|
900
|
+
};
|
|
901
|
+
assertNoPropOverlap(`factory '${definition.name}' local slot '${name}'`, provided, localProps);
|
|
902
|
+
return (0, react_jsx_runtime.jsx)(FactoryErrorBoundary, {
|
|
903
|
+
name: `${definition.name}:${name}`,
|
|
904
|
+
onEntryError: (error) => {
|
|
905
|
+
host.reportFactoryError(definition.name, localOwner, error);
|
|
906
|
+
},
|
|
907
|
+
children: (0, react_jsx_runtime.jsx)(Selected, {
|
|
908
|
+
...provided,
|
|
909
|
+
...localProps
|
|
910
|
+
})
|
|
911
|
+
}, `${definition.name}:${name}:${localScopeIdentity}`);
|
|
912
|
+
};
|
|
913
|
+
}, [
|
|
914
|
+
Selected,
|
|
915
|
+
declared.scope,
|
|
916
|
+
definition,
|
|
917
|
+
host,
|
|
918
|
+
name,
|
|
919
|
+
usesFallback
|
|
920
|
+
]);
|
|
921
|
+
}
|
|
922
|
+
function assertNoPropOverlap(owner, provided, received) {
|
|
923
|
+
for (const name of Object.keys(received)) if (Object.hasOwn(provided, name)) throw new SlotAssemblyError(`${owner} received duplicate prop '${name}'`);
|
|
924
|
+
}
|
|
925
|
+
function factoryKit(host, definition, rootBinding, scopeBinding, occurrence) {
|
|
926
|
+
const standard = standardProps(definition.scope, rootBinding, scopeBinding);
|
|
927
|
+
const registrationKit = { renderFactorySlot: boundRenderFactorySlot(definition) };
|
|
928
|
+
if (definition.locale !== void 0) {
|
|
929
|
+
const face = host.locale;
|
|
930
|
+
if (face === void 0) throw new SlotAssemblyError(`factory declares locale namespace '${definition.locale}' but no locale face is installed`);
|
|
931
|
+
registrationKit["t"] = localeSeat(face, definition.locale);
|
|
932
|
+
}
|
|
933
|
+
const scoped = scopeBinding?.key === void 0 ? void 0 : scopeBinding;
|
|
934
|
+
const store = host.factoryStoreOf(definition, scoped, occurrence);
|
|
935
|
+
if (store !== void 0) {
|
|
936
|
+
registrationKit["useStore"] = observableHook(store);
|
|
937
|
+
registrationKit["actions"] = store.actions;
|
|
938
|
+
}
|
|
939
|
+
if (definition.children !== void 0) {
|
|
940
|
+
registrationKit["renderSlot"] = boundFactoryRenderSlot(host, definition);
|
|
941
|
+
if (Object.values(definition.children).some((spec) => spec.kind === "chain")) registrationKit["renderSlotChain"] = boundFactoryRenderSlotChain(host, definition);
|
|
942
|
+
if (Object.values(definition.children).some((spec) => spec.scope !== "root")) {
|
|
943
|
+
const sessionAdapter = host.scope("session");
|
|
944
|
+
if (sessionAdapter === void 0) throw new SlotAssemblyError("factory declares a session child without an installed 'session' scope adapter");
|
|
945
|
+
registrationKit["SessionProvider"] = scopeAreaProvider(sessionAdapter);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return {
|
|
949
|
+
kit: {
|
|
950
|
+
...standard,
|
|
951
|
+
...registrationKit
|
|
952
|
+
},
|
|
953
|
+
registrationKit,
|
|
954
|
+
actions: store?.actions
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function FactoryOccurrence({ definition, inputProps, selected, caller, binding, maybeEpoch }) {
|
|
958
|
+
if (definition.scope === "root") return (0, react_jsx_runtime.jsx)(FactoryOccurrenceBody, {
|
|
959
|
+
definition,
|
|
960
|
+
inputProps,
|
|
961
|
+
selected,
|
|
962
|
+
caller
|
|
963
|
+
});
|
|
964
|
+
if (definition.scope === "session") {
|
|
965
|
+
if (binding.key === void 0) throw new SlotAssemblyError(`strict session factory '${definition.name}' rendered without a scope binding`);
|
|
966
|
+
return (0, react_jsx_runtime.jsx)(FactoryOccurrenceBody, {
|
|
967
|
+
definition,
|
|
968
|
+
inputProps,
|
|
969
|
+
selected,
|
|
970
|
+
caller,
|
|
971
|
+
scopeBinding: binding
|
|
972
|
+
}, sessionGenerationKeyOf(binding));
|
|
973
|
+
}
|
|
974
|
+
return (0, react_jsx_runtime.jsx)(FactoryOccurrenceBody, {
|
|
975
|
+
definition,
|
|
976
|
+
inputProps,
|
|
977
|
+
selected,
|
|
978
|
+
caller,
|
|
979
|
+
scopeBinding: binding
|
|
980
|
+
}, maybeEpoch);
|
|
981
|
+
}
|
|
982
|
+
function FactoryOccurrenceBody({ definition, inputProps, selected, caller, scopeBinding }) {
|
|
983
|
+
const host = useHost();
|
|
984
|
+
const rootBinding = useRootBinding();
|
|
985
|
+
const occurrence = (0, react.useRef)({}).current;
|
|
986
|
+
const localeRevision = useLocaleRevision(host.locale);
|
|
987
|
+
(0, react.useEffect)(() => host.retainFactoryOccurrence(definition, occurrence), [
|
|
988
|
+
definition,
|
|
989
|
+
host,
|
|
990
|
+
occurrence
|
|
991
|
+
]);
|
|
992
|
+
const { kit, registrationKit, actions } = (0, react.useMemo)(() => factoryKit(host, definition, rootBinding, scopeBinding, occurrence), [
|
|
993
|
+
definition,
|
|
994
|
+
host,
|
|
995
|
+
localeRevision,
|
|
996
|
+
occurrence,
|
|
997
|
+
rootBinding,
|
|
998
|
+
scopeBinding
|
|
999
|
+
]);
|
|
1000
|
+
const injected = (0, react.useMemo)(() => runInject(definition, scopeBinding, actions), [
|
|
1001
|
+
actions,
|
|
1002
|
+
definition,
|
|
1003
|
+
scopeBinding
|
|
1004
|
+
]);
|
|
1005
|
+
assertNoPropOverlap(`factory '${definition.name}' inject`, kit, injected);
|
|
1006
|
+
const provided = {
|
|
1007
|
+
...kit,
|
|
1008
|
+
...injected,
|
|
1009
|
+
useFactorySlot: useFactorySlotRuntime
|
|
1010
|
+
};
|
|
1011
|
+
assertNoPropOverlap(`factory '${definition.name}' occurrence`, provided, inputProps);
|
|
1012
|
+
const context = (0, react.useMemo)(() => ({
|
|
1013
|
+
host,
|
|
1014
|
+
definition,
|
|
1015
|
+
selected,
|
|
1016
|
+
registrationKit: {
|
|
1017
|
+
...registrationKit,
|
|
1018
|
+
...injected
|
|
1019
|
+
},
|
|
1020
|
+
rootBinding,
|
|
1021
|
+
caller
|
|
1022
|
+
}), [
|
|
1023
|
+
caller,
|
|
1024
|
+
definition,
|
|
1025
|
+
host,
|
|
1026
|
+
injected,
|
|
1027
|
+
registrationKit,
|
|
1028
|
+
rootBinding,
|
|
1029
|
+
selected
|
|
1030
|
+
]);
|
|
1031
|
+
const Comp = definition.component;
|
|
1032
|
+
return (0, react_jsx_runtime.jsx)(FactoryOccurrenceContext.Provider, {
|
|
1033
|
+
value: context,
|
|
1034
|
+
children: (0, react_jsx_runtime.jsx)(Comp, {
|
|
1035
|
+
...provided,
|
|
1036
|
+
...inputProps
|
|
1037
|
+
})
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
function FactoryOutlet({ name, inputProps, slots: selected = EMPTY_FACTORY_SELECTION, fallback, caller }) {
|
|
1041
|
+
const host = useHost();
|
|
1042
|
+
const ancestors = (0, react.useContext)(FactoryAncestryContext);
|
|
1043
|
+
const binding = useScopeBinding();
|
|
1044
|
+
const maybeEpoch = useMaybeIncarnation(binding);
|
|
1045
|
+
const version = (0, react.useSyncExternalStore)((listener) => host.subscribeFactory(name, listener), () => host.getFactoryVersion(name));
|
|
1046
|
+
const definition = host.factoryOf(name);
|
|
1047
|
+
if (definition === void 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: fallback ?? null });
|
|
1048
|
+
if (ancestors.has(name)) throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`recursive render of factory '${name}'`);
|
|
1049
|
+
for (const localName of Object.keys(selected)) if (definition.slots?.[localName] === void 0) throw new _x1a0f3n9_dsh_client_ui_slots.SlotOwnershipError(`local slot '${localName}' is not declared by factory '${name}'`);
|
|
1050
|
+
const nextAncestors = new Set(ancestors).add(name);
|
|
1051
|
+
const scopeIdentity = definition.scope === "root" ? "root" : definition.scope === "session" ? binding.key === void 0 ? "session:absent" : `session:${sessionGenerationKeyOf(binding)}` : `session-maybe:${maybeEpoch}`;
|
|
1052
|
+
return (0, react_jsx_runtime.jsx)(FactoryErrorBoundary, {
|
|
1053
|
+
name,
|
|
1054
|
+
onEntryError: (error) => {
|
|
1055
|
+
host.reportFactoryError(name, definition, error);
|
|
1056
|
+
},
|
|
1057
|
+
children: (0, react_jsx_runtime.jsx)(FactoryAncestryContext.Provider, {
|
|
1058
|
+
value: nextAncestors,
|
|
1059
|
+
children: (0, react_jsx_runtime.jsx)(FactoryOccurrence, {
|
|
1060
|
+
definition,
|
|
1061
|
+
inputProps,
|
|
1062
|
+
selected,
|
|
1063
|
+
caller,
|
|
1064
|
+
binding,
|
|
1065
|
+
maybeEpoch
|
|
1066
|
+
})
|
|
1067
|
+
})
|
|
1068
|
+
}, `${name}:${version}:${scopeIdentity}`);
|
|
1069
|
+
}
|
|
744
1070
|
function StrictSessionEntry({ slotKey, entry, ownerProps, slotInjected, hookContext, hasHookContext, onEntryError }) {
|
|
745
1071
|
const binding = useScopeBinding();
|
|
746
1072
|
if (binding.key === void 0) throw new SlotAssemblyError(`strict session slot '${slotKey}' rendered without a scope binding`);
|
|
1073
|
+
const scopedBinding = binding;
|
|
747
1074
|
return (0, react_jsx_runtime.jsx)(SlotErrorBoundary, {
|
|
748
1075
|
slotKey,
|
|
749
1076
|
onEntryError,
|
|
750
1077
|
children: (0, react_jsx_runtime.jsx)(SessionEntry, {
|
|
751
1078
|
entry,
|
|
752
1079
|
ownerProps,
|
|
753
|
-
binding,
|
|
1080
|
+
binding: scopedBinding,
|
|
754
1081
|
slotKey,
|
|
755
1082
|
slotInjected,
|
|
756
1083
|
hookContext,
|
|
757
1084
|
hasHookContext
|
|
758
1085
|
})
|
|
759
|
-
},
|
|
1086
|
+
}, sessionGenerationKeyOf(scopedBinding));
|
|
760
1087
|
}
|
|
761
1088
|
/**
|
|
762
1089
|
* Anchor style shared by every outlet wrapper: `display:contents` keeps the
|
|
@@ -944,8 +1271,8 @@ window.__ModuleLoader__.load({
|
|
|
944
1271
|
* declaration injection through the caller's ctx.effect (fiber unload
|
|
945
1272
|
* collects both), the renderer installation contract (install()/renderSlot('root') +
|
|
946
1273
|
* the SlotRendererHost face), and the store INSTANCE axis — handle x scope
|
|
947
|
-
* key -> create/cache, dropped with the last holding entry,
|
|
948
|
-
*
|
|
1274
|
+
* key -> create/cache, dropped with the last holding entry, and in-memory
|
|
1275
|
+
* session instances released without clearing persisted state on scope death.
|
|
949
1276
|
*/
|
|
950
1277
|
/** Instance key for root-scoped store records (session records key by session id, so the literal cannot collide). */
|
|
951
1278
|
const ROOT_INSTANCE_KEY = "root";
|
|
@@ -954,6 +1281,7 @@ window.__ModuleLoader__.load({
|
|
|
954
1281
|
_core = new _x1a0f3n9_dsh_client_ui_slots.SlotCore();
|
|
955
1282
|
/** Store-instance axis: handle -> mounted scope, refcount, resolved instances. */
|
|
956
1283
|
_stores = /* @__PURE__ */ new Map();
|
|
1284
|
+
_factoryStores = /* @__PURE__ */ new Map();
|
|
957
1285
|
/** Latest live Context generation for each scoped store key. */
|
|
958
1286
|
_storeScopeOwners = /* @__PURE__ */ new Map();
|
|
959
1287
|
_renderer;
|
|
@@ -1149,21 +1477,22 @@ window.__ModuleLoader__.load({
|
|
|
1149
1477
|
}, `slots.installScope(${JSON.stringify(scope)})`);
|
|
1150
1478
|
}
|
|
1151
1479
|
/**
|
|
1152
|
-
* Bind
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1155
|
-
* scope
|
|
1156
|
-
* to the newest Context generation.
|
|
1480
|
+
* Bind scoped Store instances to one Context generation. Rebinding the key
|
|
1481
|
+
* drops the previous generation's memory instances before the new owner can
|
|
1482
|
+
* resolve them. Cleanup never clears persisted state, which belongs to the
|
|
1483
|
+
* durable scope key, or drops a replacement generation's instances.
|
|
1157
1484
|
*
|
|
1158
1485
|
* @param binding - materialized scope identity and its owning Context.
|
|
1159
1486
|
*/
|
|
1160
1487
|
bindStoreScope(binding) {
|
|
1161
|
-
|
|
1488
|
+
const current = this._storeScopeOwners.get(binding.key);
|
|
1489
|
+
if (current === binding.ctx) return;
|
|
1490
|
+
if (current !== void 0) this.releaseStoreScope(binding.key);
|
|
1162
1491
|
this._storeScopeOwners.set(binding.key, binding.ctx);
|
|
1163
1492
|
binding.ctx.effect(() => () => {
|
|
1164
1493
|
if (this._storeScopeOwners.get(binding.key) !== binding.ctx) return;
|
|
1165
1494
|
this._storeScopeOwners.delete(binding.key);
|
|
1166
|
-
this.
|
|
1495
|
+
this.releaseStoreScope(binding.key);
|
|
1167
1496
|
}, `slots: store scope ${binding.key}`);
|
|
1168
1497
|
}
|
|
1169
1498
|
/**
|
|
@@ -1192,7 +1521,7 @@ window.__ModuleLoader__.load({
|
|
|
1192
1521
|
* Shadowing winners per cell for a key: the first live (non-abdicated)
|
|
1193
1522
|
* entry of each cell in priority order — what outlets render; chain keys
|
|
1194
1523
|
* pass through unchanged (election consumes every entry). The raw
|
|
1195
|
-
* {@link
|
|
1524
|
+
* {@link SlotRegistry.entries} view stays the inspection surface. Fresh
|
|
1196
1525
|
* array per call, not a uSES getSnapshot source.
|
|
1197
1526
|
* @param key - SlotMap key.
|
|
1198
1527
|
* @returns the winning entry per occupied cell.
|
|
@@ -1201,22 +1530,20 @@ window.__ModuleLoader__.load({
|
|
|
1201
1530
|
return this._core.entriesOfSlot(key);
|
|
1202
1531
|
}
|
|
1203
1532
|
/**
|
|
1204
|
-
* Export the current JSON-safe Slot declaration
|
|
1205
|
-
* @param root - exact live Slot
|
|
1206
|
-
* @returns selected
|
|
1533
|
+
* Export the current JSON-safe Slot and Factory declaration trees for read-only inspection.
|
|
1534
|
+
* @param root - exact live Slot key or `factory:<name>`; omitted returns all roots.
|
|
1535
|
+
* @returns selected composition trees.
|
|
1207
1536
|
*/
|
|
1208
1537
|
snapshot(root) {
|
|
1209
1538
|
return this._core.snapshot(root);
|
|
1210
1539
|
}
|
|
1211
1540
|
/**
|
|
1212
|
-
* Observe entry
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1215
|
-
*
|
|
1216
|
-
*
|
|
1217
|
-
*
|
|
1218
|
-
* @param fn - called with the slot key, the crashed entry, the crash
|
|
1219
|
-
* cause, and `abdicated`: whether the crash retired the entry from its cell.
|
|
1541
|
+
* Observe ordinary entry and Factory occurrence crashes through one
|
|
1542
|
+
* supervision channel. Fires synchronously after any ordinary-entry
|
|
1543
|
+
* abdication mutation. Callers own the disposer (wire it through ctx.effect
|
|
1544
|
+
* for fiber-lifetime cleanup, as with {@link SlotRegistry.subscribe}).
|
|
1545
|
+
* @param fn - called with the Slot or `factory:<name>` key, crashed
|
|
1546
|
+
* registration, cause, and whether an ordinary entry was retired.
|
|
1220
1547
|
* @returns unsubscribe.
|
|
1221
1548
|
*/
|
|
1222
1549
|
onEntryError(fn) {
|
|
@@ -1269,6 +1596,29 @@ window.__ModuleLoader__.load({
|
|
|
1269
1596
|
if (store !== void 0) this._release(store);
|
|
1270
1597
|
};
|
|
1271
1598
|
}
|
|
1599
|
+
_registerFactory(options, component) {
|
|
1600
|
+
const registrant = this.ctx.fiber?.name;
|
|
1601
|
+
const erased = {
|
|
1602
|
+
...options,
|
|
1603
|
+
...registrant === void 0 ? {} : { registrant }
|
|
1604
|
+
};
|
|
1605
|
+
const dispose = this._core.registerFactory(erased, component);
|
|
1606
|
+
const definition = this._core.factory(options.name);
|
|
1607
|
+
if (definition === void 0) throw new Error(`slot factory "${options.name}" disappeared during registration`);
|
|
1608
|
+
if (definition.store !== void 0 && typeof definition.store !== "function") this._acquire(definition.store, definition.scope);
|
|
1609
|
+
else if (typeof definition.store === "function") this._factoryStores.set(definition, {
|
|
1610
|
+
occurrences: /* @__PURE__ */ new WeakMap(),
|
|
1611
|
+
mounted: /* @__PURE__ */ new Map()
|
|
1612
|
+
});
|
|
1613
|
+
let disposed = false;
|
|
1614
|
+
return () => {
|
|
1615
|
+
if (disposed) return;
|
|
1616
|
+
disposed = true;
|
|
1617
|
+
dispose();
|
|
1618
|
+
this._factoryStores.delete(definition);
|
|
1619
|
+
if (definition.store !== void 0 && typeof definition.store !== "function") this._release(definition.store);
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1272
1622
|
/** Build the domain-neutral host face once; installed adapters remain live through getters. */
|
|
1273
1623
|
hostFace() {
|
|
1274
1624
|
if (this._host !== void 0) return this._host;
|
|
@@ -1281,9 +1631,18 @@ window.__ModuleLoader__.load({
|
|
|
1281
1631
|
reportEntryError: (key, entry, error, info) => {
|
|
1282
1632
|
this._core.reportEntryError(key, entry, error, info);
|
|
1283
1633
|
},
|
|
1634
|
+
reportFactoryError: (name, registration, error) => {
|
|
1635
|
+
this._core.reportFactoryError(name, registration, error);
|
|
1636
|
+
},
|
|
1284
1637
|
specOf: (key) => this._core.specDynamic(key),
|
|
1285
1638
|
isLive: (entry) => this._core.isLive(entry),
|
|
1286
1639
|
storeOf: (entry, scopeBinding) => entry.store === void 0 ? void 0 : this.resolveStore(entry.store, scopeBinding),
|
|
1640
|
+
factoryStoreOf: (definition, scopeBinding, occurrence) => this.resolveFactoryStore(definition, scopeBinding, occurrence),
|
|
1641
|
+
retainFactoryOccurrence: (definition, occurrence) => this.retainFactoryOccurrence(definition, occurrence),
|
|
1642
|
+
subscribeFactory: (name, fn) => this._core.subscribeFactory(name, fn),
|
|
1643
|
+
getFactoryVersion: (name) => this._core.factoryVersion(name),
|
|
1644
|
+
factoryOf: (name) => this._core.factory(name),
|
|
1645
|
+
isFactoryLive: (definition) => this._core.isFactoryLive(definition),
|
|
1287
1646
|
root: this._rootSource,
|
|
1288
1647
|
scopeRevision: this._scopeRevisionSource,
|
|
1289
1648
|
scope: (scope) => service._scopes.get(scope === "session-maybe" ? "session" : scope),
|
|
@@ -1343,13 +1702,54 @@ window.__ModuleLoader__.load({
|
|
|
1343
1702
|
}
|
|
1344
1703
|
return instance;
|
|
1345
1704
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1705
|
+
resolveFactoryStore(definition, scopeBinding, occurrence) {
|
|
1706
|
+
if (!this._core.isFactoryLive(definition)) throw new _x1a0f3n9_dsh_client_ui_slots.StaleAuthorizationError(`slot factory "${definition.name}" is not registered`);
|
|
1707
|
+
const declaration = definition.store;
|
|
1708
|
+
if (declaration === void 0) return void 0;
|
|
1709
|
+
if (typeof declaration !== "function") return this.resolveStore(declaration, scopeBinding);
|
|
1710
|
+
const axis = this._factoryStores.get(definition);
|
|
1711
|
+
const scopeKey = definition.scope === "root" ? ROOT_INSTANCE_KEY : requireScopeKey(definition, scopeBinding);
|
|
1712
|
+
if (scopeBinding !== void 0 && definition.scope !== "root") this.bindStoreScope(scopeBinding);
|
|
1713
|
+
let record = axis.occurrences.get(occurrence);
|
|
1714
|
+
if (record === void 0) {
|
|
1715
|
+
const handle = declaration();
|
|
1716
|
+
if (handle.spec.persist !== void 0) throw new SlotAssemblyError(`exclusive store for factory "${definition.name}" cannot declare persistence`);
|
|
1717
|
+
record = {
|
|
1718
|
+
handle,
|
|
1719
|
+
instances: /* @__PURE__ */ new Map(),
|
|
1720
|
+
retainers: 0
|
|
1721
|
+
};
|
|
1722
|
+
axis.occurrences.set(occurrence, record);
|
|
1723
|
+
}
|
|
1724
|
+
const existing = record.instances.get(scopeKey);
|
|
1725
|
+
if (existing !== void 0) return existing;
|
|
1726
|
+
const instance = definition.scope === "root" || scopeBinding === void 0 ? record.handle.create() : record.handle.create(scopeBinding.key);
|
|
1727
|
+
record.instances.set(scopeKey, instance);
|
|
1728
|
+
return instance;
|
|
1729
|
+
}
|
|
1730
|
+
retainFactoryOccurrence(definition, occurrence) {
|
|
1731
|
+
if (!this._core.isFactoryLive(definition)) return () => {};
|
|
1732
|
+
if (typeof definition.store !== "function") return () => {};
|
|
1733
|
+
const axis = this._factoryStores.get(definition);
|
|
1734
|
+
const record = axis.occurrences.get(occurrence);
|
|
1735
|
+
record.retainers += 1;
|
|
1736
|
+
axis.mounted.set(occurrence, record);
|
|
1737
|
+
let released = false;
|
|
1738
|
+
return () => {
|
|
1739
|
+
if (released) return;
|
|
1740
|
+
released = true;
|
|
1741
|
+
record.retainers -= 1;
|
|
1742
|
+
if (record.retainers !== 0) return;
|
|
1743
|
+
axis.mounted.delete(occurrence);
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
/** Drop every materialized non-root Store instance for one ended Context generation. */
|
|
1747
|
+
releaseStoreScope(key) {
|
|
1748
|
+
for (const record of this._stores.values()) {
|
|
1349
1749
|
if (record.scope === "root") continue;
|
|
1350
|
-
(record.instances.get(key) ?? handle.create(key)).clearPersisted();
|
|
1351
1750
|
record.instances.delete(key);
|
|
1352
1751
|
}
|
|
1752
|
+
for (const axis of this._factoryStores.values()) for (const record of axis.mounted.values()) record.instances.delete(key);
|
|
1353
1753
|
}
|
|
1354
1754
|
/** Bind (or re-reference) a handle on the axis; cross-scope conflicts already threw in the core. */
|
|
1355
1755
|
_acquire(handle, scope) {
|
|
@@ -1389,6 +1789,14 @@ window.__ModuleLoader__.load({
|
|
|
1389
1789
|
const options = rawOptions;
|
|
1390
1790
|
return this.ctx.effect(() => this["_register"](options, component), "slots.register()");
|
|
1391
1791
|
};
|
|
1792
|
+
SlotRegistry.prototype.registerFactory = function registerFactory(rawOptions, component) {
|
|
1793
|
+
const options = rawOptions;
|
|
1794
|
+
return this.ctx.effect(() => this["_registerFactory"](options, component), "slots.registerFactory()");
|
|
1795
|
+
};
|
|
1796
|
+
function requireScopeKey(definition, binding) {
|
|
1797
|
+
if (binding === void 0) throw new Error(`${definition.scope} factory store resolution requires a session id`);
|
|
1798
|
+
return binding.key;
|
|
1799
|
+
}
|
|
1392
1800
|
//#endregion
|
|
1393
1801
|
//#region lib/types/client/index.js
|
|
1394
1802
|
/**
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/** Internal React bindings for renderer hosts and standard-source scopes. */
|
|
2
2
|
import { type ReactNode } from 'react';
|
|
3
3
|
import type { HostObservable, KeyedStandardSource, MaybeSnapshotSelectorHook, SlotRendererHost, SnapshotSelectorHook, StandardSourceBinding } from '@x1a0f3n9/dsh-client-ui-slots';
|
|
4
|
-
/** Missing renderer assembly dependency. */
|
|
5
|
-
export declare class SlotAssemblyError extends Error {
|
|
6
|
-
}
|
|
7
4
|
/** In-package renderer host context. */
|
|
8
5
|
export declare const HostContext: import("react").Context<SlotRendererHost | null>;
|
|
9
6
|
/**
|
|
@@ -21,6 +18,17 @@ export declare function useRootBinding(): StandardSourceBinding;
|
|
|
21
18
|
* @returns a binding whose key is absent when no Session is selected.
|
|
22
19
|
*/
|
|
23
20
|
export declare function useScopeBinding(): StandardSourceBinding;
|
|
21
|
+
/**
|
|
22
|
+
* Publish one resolved scope binding to a renderer subtree.
|
|
23
|
+
* @param props - provider inputs.
|
|
24
|
+
* @param props.binding - binding exposed to scoped entries.
|
|
25
|
+
* @param props.children - subtree that inherits the binding.
|
|
26
|
+
* @returns the scoped React provider.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ScopeBindingProvider({ binding, children }: {
|
|
29
|
+
binding: StandardSourceBinding;
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
}): ReactNode;
|
|
24
32
|
/**
|
|
25
33
|
* Bind one observable source to an identity-stable selector Hook.
|
|
26
34
|
* @param source - observable source.
|
|
@@ -34,13 +42,13 @@ export declare function observableHook<T>(source: HostObservable<T>): SnapshotSe
|
|
|
34
42
|
*/
|
|
35
43
|
export declare function maybeObservableHook<T>(source: HostObservable<T> | undefined): MaybeSnapshotSelectorHook<T>;
|
|
36
44
|
/** Erased open-key selector Hook synthesized from one keyed source family. */
|
|
37
|
-
export type KeyedSnapshotHook = (
|
|
45
|
+
export type KeyedSnapshotHook = (keyOrSelector: string | ((value: unknown) => unknown), selectorOrEqual?: ((value: unknown) => unknown) | ((left: unknown, right: unknown) => boolean), equal?: (left: unknown, right: unknown) => boolean) => unknown;
|
|
38
46
|
/**
|
|
39
47
|
* Bind an open-key source family.
|
|
40
48
|
* @param source - keyed resolver, or absence for an optional scope.
|
|
41
49
|
* @returns cached keyed selector Hook.
|
|
42
50
|
*/
|
|
43
|
-
export declare function keyedObservableHook(source: KeyedStandardSource | undefined): KeyedSnapshotHook;
|
|
51
|
+
export declare function keyedObservableHook(source: KeyedStandardSource | undefined, defaultKey?: string): KeyedSnapshotHook;
|
|
44
52
|
/** Subscribe the tree to the atomically assembled root standard-source roster. */
|
|
45
53
|
export declare function RootStandardProvider({ children }: {
|
|
46
54
|
children: ReactNode;
|
|
@@ -15,7 +15,8 @@ export interface UiRendererService {
|
|
|
15
15
|
declare module '@deepseek-ai/cordis' {
|
|
16
16
|
interface Events {
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* An ordinary Slot declaration or entry registration set changed. Factory
|
|
19
|
+
* definitions publish through `subscribeFactory()` instead.
|
|
19
20
|
* @mode emit
|
|
20
21
|
* @param key - mutated SlotMap key.
|
|
21
22
|
*/
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
* declaration injection through the caller's ctx.effect (fiber unload
|
|
7
7
|
* collects both), the renderer installation contract (install()/renderSlot('root') +
|
|
8
8
|
* the SlotRendererHost face), and the store INSTANCE axis — handle x scope
|
|
9
|
-
* key -> create/cache, dropped with the last holding entry,
|
|
10
|
-
*
|
|
9
|
+
* key -> create/cache, dropped with the last holding entry, and in-memory
|
|
10
|
+
* session instances released without clearing persisted state on scope death.
|
|
11
11
|
*/
|
|
12
12
|
import { Service } from '@deepseek-ai/cordis';
|
|
13
13
|
import type { Context } from '@deepseek-ai/cordis';
|
|
14
14
|
import { SlotCore } from '@x1a0f3n9/dsh-client-ui-slots';
|
|
15
|
-
import type {
|
|
15
|
+
import type { LiveCompositionNode, LocaleFace, OwnerOf, RegisterFactory, SlotMap, SlotRenderer, RootStandardSourceContribution, ScopedStandardSourceBinding, SlotScope, SlotScopeAdapter, SlotSpec, StoredFactory, StoredEntry } from '@x1a0f3n9/dsh-client-ui-slots';
|
|
16
16
|
declare module '@x1a0f3n9/dsh-client-ui-slots' {
|
|
17
17
|
interface SlotMap {
|
|
18
18
|
/**
|
|
@@ -47,6 +47,7 @@ export declare class SlotRegistry extends Service {
|
|
|
47
47
|
private readonly _core;
|
|
48
48
|
/** Store-instance axis: handle -> mounted scope, refcount, resolved instances. */
|
|
49
49
|
private readonly _stores;
|
|
50
|
+
private readonly _factoryStores;
|
|
50
51
|
/** Latest live Context generation for each scoped store key. */
|
|
51
52
|
private readonly _storeScopeOwners;
|
|
52
53
|
private _renderer;
|
|
@@ -65,7 +66,7 @@ export declare class SlotRegistry extends Service {
|
|
|
65
66
|
*/
|
|
66
67
|
constructor(ctx: Context);
|
|
67
68
|
/**
|
|
68
|
-
* The
|
|
69
|
+
* The ordinary Slot registration API. The typed face IS the core's register
|
|
69
70
|
* (both overloads reused verbatim — one authority, no structural copy;
|
|
70
71
|
* see SlotCore.register for children declaration, store seat, inject
|
|
71
72
|
* face, load-time validation, and the unload cascade). This layer adds:
|
|
@@ -82,6 +83,16 @@ export declare class SlotRegistry extends Service {
|
|
|
82
83
|
* own root ctx and silently break per-plugin disposal.
|
|
83
84
|
*/
|
|
84
85
|
readonly register: SlotCore['register'];
|
|
86
|
+
/**
|
|
87
|
+
* Register one reusable Component Factory under the caller's effect lifetime.
|
|
88
|
+
* A Store factory mints one handle per rendered occurrence rather than per
|
|
89
|
+
* definition. Like {@link SlotRegistry.register}, this remains a prototype
|
|
90
|
+
* method so the Cordis proxy binds `this.ctx` to the caller's Context.
|
|
91
|
+
* @param options - runtime definition checked against `SlotFactoryMap`.
|
|
92
|
+
* @param component - reusable Factory Component.
|
|
93
|
+
* @returns the idempotent definition disposer.
|
|
94
|
+
*/
|
|
95
|
+
readonly registerFactory: RegisterFactory;
|
|
85
96
|
/**
|
|
86
97
|
* Install an effect for each declaration lifetime of a slot. The callback
|
|
87
98
|
* runs synchronously when the declaration already exists; otherwise it runs
|
|
@@ -128,11 +139,10 @@ export declare class SlotRegistry extends Service {
|
|
|
128
139
|
*/
|
|
129
140
|
installScope(scope: Exclude<SlotScope, 'root' | 'session-maybe'>, adapter: SlotScopeAdapter): void;
|
|
130
141
|
/**
|
|
131
|
-
* Bind
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* scope
|
|
135
|
-
* to the newest Context generation.
|
|
142
|
+
* Bind scoped Store instances to one Context generation. Rebinding the key
|
|
143
|
+
* drops the previous generation's memory instances before the new owner can
|
|
144
|
+
* resolve them. Cleanup never clears persisted state, which belongs to the
|
|
145
|
+
* durable scope key, or drops a replacement generation's instances.
|
|
136
146
|
*
|
|
137
147
|
* @param binding - materialized scope identity and its owning Context.
|
|
138
148
|
*/
|
|
@@ -156,30 +166,28 @@ export declare class SlotRegistry extends Service {
|
|
|
156
166
|
* Shadowing winners per cell for a key: the first live (non-abdicated)
|
|
157
167
|
* entry of each cell in priority order — what outlets render; chain keys
|
|
158
168
|
* pass through unchanged (election consumes every entry). The raw
|
|
159
|
-
* {@link
|
|
169
|
+
* {@link SlotRegistry.entries} view stays the inspection surface. Fresh
|
|
160
170
|
* array per call, not a uSES getSnapshot source.
|
|
161
171
|
* @param key - SlotMap key.
|
|
162
172
|
* @returns the winning entry per occupied cell.
|
|
163
173
|
*/
|
|
164
174
|
entriesOfSlot(key: keyof SlotMap & string): readonly StoredEntry[];
|
|
165
175
|
/**
|
|
166
|
-
* Export the current JSON-safe Slot declaration
|
|
167
|
-
* @param root - exact live Slot
|
|
168
|
-
* @returns selected
|
|
176
|
+
* Export the current JSON-safe Slot and Factory declaration trees for read-only inspection.
|
|
177
|
+
* @param root - exact live Slot key or `factory:<name>`; omitted returns all roots.
|
|
178
|
+
* @returns selected composition trees.
|
|
169
179
|
*/
|
|
170
|
-
snapshot(root?: string):
|
|
180
|
+
snapshot(root?: string): LiveCompositionNode[];
|
|
171
181
|
/**
|
|
172
|
-
* Observe entry
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* @param fn - called with the slot key, the crashed entry, the crash
|
|
179
|
-
* cause, and `abdicated`: whether the crash retired the entry from its cell.
|
|
182
|
+
* Observe ordinary entry and Factory occurrence crashes through one
|
|
183
|
+
* supervision channel. Fires synchronously after any ordinary-entry
|
|
184
|
+
* abdication mutation. Callers own the disposer (wire it through ctx.effect
|
|
185
|
+
* for fiber-lifetime cleanup, as with {@link SlotRegistry.subscribe}).
|
|
186
|
+
* @param fn - called with the Slot or `factory:<name>` key, crashed
|
|
187
|
+
* registration, cause, and whether an ordinary entry was retired.
|
|
180
188
|
* @returns unsubscribe.
|
|
181
189
|
*/
|
|
182
|
-
onEntryError(fn: (key: string,
|
|
190
|
+
onEntryError(fn: (key: string, registration: StoredEntry | StoredFactory, error: unknown, info: {
|
|
183
191
|
abdicated: boolean;
|
|
184
192
|
}) => void): () => void;
|
|
185
193
|
/**
|
|
@@ -203,6 +211,7 @@ export declare class SlotRegistry extends Service {
|
|
|
203
211
|
getVersion(key: keyof SlotMap & string): number;
|
|
204
212
|
/** Delegating registration path: factory minting + registrant stamp + core write + instance-axis bookkeeping. */
|
|
205
213
|
private _register;
|
|
214
|
+
private _registerFactory;
|
|
206
215
|
/** Build the domain-neutral host face once; installed adapters remain live through getters. */
|
|
207
216
|
private hostFace;
|
|
208
217
|
/** Validate and atomically publish the current root contribution roster. */
|
|
@@ -211,8 +220,10 @@ export declare class SlotRegistry extends Service {
|
|
|
211
220
|
private publishScopeRevision;
|
|
212
221
|
/** Resolve (create or reuse) the store instance for a registered handle under a scope key. */
|
|
213
222
|
private resolveStore;
|
|
214
|
-
|
|
215
|
-
private
|
|
223
|
+
private resolveFactoryStore;
|
|
224
|
+
private retainFactoryOccurrence;
|
|
225
|
+
/** Drop every materialized non-root Store instance for one ended Context generation. */
|
|
226
|
+
private releaseStoreScope;
|
|
216
227
|
/** Bind (or re-reference) a handle on the axis; cross-scope conflicts already threw in the core. */
|
|
217
228
|
private _acquire;
|
|
218
229
|
/** Drop one reference; the last holder's unload drops the record (instances go with it — engine stores need no explicit dispose). */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x1a0f3n9/dsh-client-ui-renderer",
|
|
3
3
|
"description": "Browser UI renderer: React slot bindings, ctx.uiRenderer, and the assembled application root",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7-rc.3",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@deepseek-ai/cordis": "
|
|
40
|
+
"@deepseek-ai/cordis": "~4.0.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/react": "~18.3.1",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"react": "^18.2.0",
|
|
47
47
|
"react-dom": "^18.2.0",
|
|
48
48
|
"use-sync-external-store": "1.2.0",
|
|
49
|
-
"@deepseek-ai/cordis": "
|
|
50
|
-
"@x1a0f3n9/dsh-client-test-runtime": "
|
|
51
|
-
"@x1a0f3n9/dsh-client-ui-slots": "
|
|
52
|
-
"@x1a0f3n9/dsh-invariants": "
|
|
49
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
50
|
+
"@x1a0f3n9/dsh-client-test-runtime": "0.1.7-rc.3",
|
|
51
|
+
"@x1a0f3n9/dsh-client-ui-slots": "0.1.7-rc.3",
|
|
52
|
+
"@x1a0f3n9/dsh-invariants": "0.1.7-rc.3"
|
|
53
53
|
},
|
|
54
54
|
"files": [
|
|
55
55
|
"lib/index.js",
|