@opetope/react 0.6.0 → 0.7.0
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/CHANGELOG.md +31 -0
- package/README.md +30 -7
- package/README.ru.md +30 -7
- package/dist/command-hook-controller.d.ts +2 -1
- package/dist/command-hook.d.ts +5 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @opetope/react
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 538cdfe: Replace Lookup/fromOptional with Maybe/fromMaybe and some/none branches across collections, registries and optional imports. Add pure maybe operations and reactive projections that preserve absence unless a fallback is supplied.
|
|
8
|
+
|
|
9
|
+
Select a single dependency method with call(source, key), or several with calls(source, keys). Support optional host and feature providers, including inside models, and an explicit whenMissing: 'none' outcome while preserving provider failures, cancellation and physical ownership. Existing custom call({ run }) remains available. This alpha release removes the former names.
|
|
10
|
+
|
|
11
|
+
Devtools weak edges now carry presence: some/none. Graph schema 5 and frame schema 4 reject the previous lookup field and revisions.
|
|
12
|
+
|
|
13
|
+
- 538cdfe: Add a stable `.handler` to inputless CommandHook values returned by useCommand, useCommands and useModel selections. Use onClick={logout.handler} to ignore the React event and invoke the command with undefined. Retain .run for explicit inputs, callbacks, signals and CommandOutcome. Preserve immutable status snapshots, errors, cancellation and binding lifetime.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 538cdfe: Make computed accept its calculation first: computed(get => value, options?). The injected get tracks each Readable used by the calculation; the optional second argument supplies result equality. Remove the former object argument without a compatibility overload.
|
|
18
|
+
|
|
19
|
+
Keep derive({ from, select }) for explicit sources and preserve the existing reactive scheduling and lifetime behavior. Migrate framework consumers and add a compile-checked model example in the English and Russian guides.
|
|
20
|
+
|
|
21
|
+
- 538cdfe: Replace singleFlight with dedupe on custom Calls. Use dedupe: true to share one pending or running execution per Call and generation, or a key function to share equivalent inputs. Retain the first input and independent caller cancellation. Remove the former name without a compatibility alias.
|
|
22
|
+
|
|
23
|
+
Reject both forms of dedupe with policy: latest in types and at runtime. Different keys keep one FIFO under queue and run independently under parallel. Preserve once caching before deduplication and keep scheduling options on Call declarations rather than React hooks. Add a compile-checked model example and update the English and Russian guides.
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [538cdfe]
|
|
26
|
+
- Updated dependencies [538cdfe]
|
|
27
|
+
- Updated dependencies [538cdfe]
|
|
28
|
+
- Updated dependencies [538cdfe]
|
|
29
|
+
- Updated dependencies [538cdfe]
|
|
30
|
+
- Updated dependencies [538cdfe]
|
|
31
|
+
- @opetope/core@0.7.0
|
|
32
|
+
- @opetope/runtime@0.7.0
|
|
33
|
+
|
|
3
34
|
## 0.6.0
|
|
4
35
|
|
|
5
36
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -31,14 +31,14 @@ const CounterSlot = defineSlot<{ readonly label: string }>({ id: 'example.counte
|
|
|
31
31
|
const CounterButton = requiresModels([CounterModel])(({ label }: { readonly label: string }) => {
|
|
32
32
|
const {
|
|
33
33
|
count,
|
|
34
|
-
increment: { inFlight, lastError
|
|
34
|
+
increment: { handler, inFlight, lastError },
|
|
35
35
|
} = useModel(CounterModel, (model, { read }) => ({
|
|
36
36
|
count: read(model.count),
|
|
37
37
|
increment: model.increment,
|
|
38
38
|
}));
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
|
-
<button disabled={inFlight} onClick={
|
|
41
|
+
<button disabled={inFlight} onClick={handler}>
|
|
42
42
|
{lastError ? 'Retry' : `${label}: ${count}`}
|
|
43
43
|
</button>
|
|
44
44
|
);
|
|
@@ -53,8 +53,15 @@ A component gets neither a service, nor a class, nor a runtime ref. The contribu
|
|
|
53
53
|
model declares it with `requiresModels`. `useModel` reads exactly that authority frame. `useCommand` returns `{ run, inFlight, result, lastError }`
|
|
54
54
|
and always resolves the outcome, so a normal cancellation never becomes an unhandled rejection (D116).
|
|
55
55
|
|
|
56
|
-
`
|
|
57
|
-
`
|
|
56
|
+
For `Call<void, Output>` and `Call<undefined, Output>`, the hook also exposes `handler: () => void` (D278).
|
|
57
|
+
Use `onClick={logout.handler}`: it ignores the React event and invokes the Call with `undefined`.
|
|
58
|
+
Commands with data, including `T | undefined`, `unknown`, `any` and `never`, do not expose a handler in their type.
|
|
59
|
+
Use `run(input, options?)` for data, an outcome, callbacks or a per-run signal. The handler reports failures through
|
|
60
|
+
`lastError` and preserves the same cancellation behavior; it returns no promise or outcome.
|
|
61
|
+
|
|
62
|
+
`run` and `handler` are stable while the invoker stays the same; the returned object changes as `inFlight`, `result`
|
|
63
|
+
or `lastError` changes. Destructure the function for effect dependencies. A handler captured from a replaced or
|
|
64
|
+
unmounted consumer is fenced; it does not start work on the replacement.
|
|
58
65
|
|
|
59
66
|
The hook schedules nothing. Every `run` reaches the call, and the policy the call was created with decides what
|
|
60
67
|
happens to it (D203). For an absolute value setter the model declares `policy: 'latest'` in `context.call`, and the
|
|
@@ -63,6 +70,10 @@ input signal is refused as `cancelled` without reaching the call, a run of an un
|
|
|
63
70
|
way, `inFlight` is true while any run this consumer started is unsettled, and every run carries its own callbacks
|
|
64
71
|
and signal.
|
|
65
72
|
|
|
73
|
+
To share equivalent pending or running work, the model declares `dedupe: true` or `dedupe: input => key`
|
|
74
|
+
on `context.call`. Sharing keeps the first input and each caller's independent cancellation; neither form may
|
|
75
|
+
be combined with `latest` (D277). These are Call options, not hook options.
|
|
76
|
+
|
|
66
77
|
For several commands use an object selection (D174):
|
|
67
78
|
|
|
68
79
|
```tsx
|
|
@@ -91,6 +102,18 @@ A model selection can use a named interface without an index signature (D217). I
|
|
|
91
102
|
arrays, functions, constructors and built-in collection/date/promise objects are not selection records.
|
|
92
103
|
`read(source)` returns its snapshot; `read(source, project)` returns a projection. Authentic Calls selected as record
|
|
93
104
|
fields become the same `CommandHook` as `useCommands`, including independent alias statuses and stable `.run`.
|
|
105
|
+
The same inputless `.handler` is available in `useCommands` and model selections. A single selected command needs
|
|
106
|
+
no nested hooks:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
const { logout } = useModel(AuthModel, auth => ({ logout: auth.logout }));
|
|
110
|
+
return (
|
|
111
|
+
<button disabled={logout.inFlight} onClick={logout.handler}>
|
|
112
|
+
Log out
|
|
113
|
+
</button>
|
|
114
|
+
);
|
|
115
|
+
```
|
|
116
|
+
|
|
94
117
|
The one-argument form still returns the granted model; individual hooks remain available.
|
|
95
118
|
|
|
96
119
|
Only explicitly read sources are subscribed, once per distinct Readable in the selection. Returned data fields are
|
|
@@ -234,11 +257,11 @@ a scoped zero-count assertion, without proving absence of arbitrary host, UI or
|
|
|
234
257
|
application imports and internal renderer references. A failed cleanup promise can retain original errors and retry
|
|
235
258
|
capabilities; a caller that keeps `mounted.host` also keeps its own renderer result.
|
|
236
259
|
|
|
237
|
-
The inspection schemas are `opetope.devtools-graph/
|
|
238
|
-
`opetope.runtime-activity/1` snapshots (D266). Within one session,
|
|
260
|
+
The inspection schemas are `opetope.devtools-graph/5` and `opetope.devtools-frame/4`, with optional
|
|
261
|
+
`opetope.runtime-activity/1` snapshots (D266, D275). Within one session,
|
|
239
262
|
a frame without `activity` preserves the previous activity; a full snapshot/reset without it clears that observation
|
|
240
263
|
(D216). Activity-bearing frames replace the previous activity in full.
|
|
241
|
-
Use matching runtime/devtools versions: graph
|
|
264
|
+
Use matching runtime/devtools versions: previous graph/frame revisions are rejected; weak-edge presence requires graph `/5` and frame `/4`. Activity identifies the execution,
|
|
242
265
|
actual feature generation, physical Calls, exact current lane blockers, registered resource leases and load attempts.
|
|
243
266
|
Host demand and UI models are unknown; stream observation covers state, not physical load identities. `freshness`
|
|
244
267
|
and `truncated` distinguish a complete live view from a partial or detached one. A closed session is stale;
|
package/README.ru.md
CHANGED
|
@@ -31,14 +31,14 @@ const CounterSlot = defineSlot<{ readonly label: string }>({ id: 'example.counte
|
|
|
31
31
|
const CounterButton = requiresModels([CounterModel])(({ label }: { readonly label: string }) => {
|
|
32
32
|
const {
|
|
33
33
|
count,
|
|
34
|
-
increment: { inFlight, lastError
|
|
34
|
+
increment: { handler, inFlight, lastError },
|
|
35
35
|
} = useModel(CounterModel, (model, { read }) => ({
|
|
36
36
|
count: read(model.count),
|
|
37
37
|
increment: model.increment,
|
|
38
38
|
}));
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
|
-
<button disabled={inFlight} onClick={
|
|
41
|
+
<button disabled={inFlight} onClick={handler}>
|
|
42
42
|
{lastError ? 'Retry' : `${label}: ${count}`}
|
|
43
43
|
</button>
|
|
44
44
|
);
|
|
@@ -54,8 +54,15 @@ function CounterArea() {
|
|
|
54
54
|
авторитета. `useCommand` отдаёт `{ run, inFlight, result, lastError }`
|
|
55
55
|
и всегда resolve-ит исход, поэтому штатная отмена не становится unhandled rejection (D116).
|
|
56
56
|
|
|
57
|
-
`
|
|
58
|
-
|
|
57
|
+
Для `Call<void, Output>` и `Call<undefined, Output>` хук также предоставляет `handler: () => void` (D278).
|
|
58
|
+
Пишите `onClick={logout.handler}`: обработчик игнорирует React event и вызывает Call с `undefined`.
|
|
59
|
+
У команд с данными, включая `T | undefined`, `unknown`, `any` и `never`, handler недоступен в типе.
|
|
60
|
+
Для данных, исхода, callbacks или сигнала отдельного вызова используйте `run(input, options?)`. Handler показывает
|
|
61
|
+
ошибки через `lastError` и сохраняет обработку отмены; promise или исход он не возвращает.
|
|
62
|
+
|
|
63
|
+
`run` и `handler` стабильны, пока invoker тот же; возвращённый объект меняется вместе с `inFlight`, `result` или
|
|
64
|
+
`lastError`. Для зависимостей эффекта берите функцию деструктуризацией. Сохранённый handler заменённого или
|
|
65
|
+
размонтированного потребителя закрыт для новых вызовов и не перенаправляет работу на замену.
|
|
59
66
|
|
|
60
67
|
Хук ничего не планирует. Каждый `run` доходит до вызова, и решает политика, с которой вызов создан (D203). Для
|
|
61
68
|
setter абсолютного значения модель объявляет `policy: 'latest'` в `context.call`, и новый вход заменяет ожидающий
|
|
@@ -63,6 +70,10 @@ setter абсолютного значения модель объявляет `
|
|
|
63
70
|
доходя до вызова, `run` размонтированного потребителя отвергается так же, `inFlight` истинен, пока не завершился
|
|
64
71
|
хоть один начатый им прогон, и у каждого прогона свои callbacks и signal.
|
|
65
72
|
|
|
73
|
+
Чтобы объединить эквивалентную ожидающую или исполняющуюся работу, модель объявляет `dedupe: true` либо
|
|
74
|
+
`dedupe: input => key` у `context.call`. Сохраняются первый вход и независимая отмена каждого вызывающего;
|
|
75
|
+
обе формы запрещены с `latest` (D277). Это опции Call, а не хука.
|
|
76
|
+
|
|
66
77
|
Для нескольких команд используйте объектный выбор (D174):
|
|
67
78
|
|
|
68
79
|
```tsx
|
|
@@ -91,6 +102,18 @@ const saving = save.inFlight;
|
|
|
91
102
|
arrays, functions, constructors и встроенные объекты коллекций, дат и promises не являются selection records.
|
|
92
103
|
`read(source)` возвращает снимок; `read(source, project)` — проекцию. Authentic Calls, выбранные полями record,
|
|
93
104
|
превращаются в тот же `CommandHook`, что у `useCommands`, с независимыми статусами aliases и стабильным `.run`.
|
|
105
|
+
Тот же `.handler` для команды без входа доступен в `useCommands` и выборе модели. Одну команду можно выбрать без
|
|
106
|
+
вложенных hooks:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
const { logout } = useModel(AuthModel, auth => ({ logout: auth.logout }));
|
|
110
|
+
return (
|
|
111
|
+
<button disabled={logout.inFlight} onClick={logout.handler}>
|
|
112
|
+
Log out
|
|
113
|
+
</button>
|
|
114
|
+
);
|
|
115
|
+
```
|
|
116
|
+
|
|
94
117
|
Форма с одним аргументом по-прежнему возвращает выданную модель; отдельные hooks сохраняются.
|
|
95
118
|
|
|
96
119
|
Подписка создаётся только на явно прочитанные источники, одна на каждый различный Readable внутри selection.
|
|
@@ -234,11 +257,11 @@ Deadline готовности также оставляет приложение
|
|
|
234
257
|
host/UI/GC-утечек. Успешный cleanup очищает imports приложения и внутренние ссылки на renderer. Promise отказавшего
|
|
235
258
|
cleanup может удерживать исходные ошибки и retry capabilities; сохранённый пользователем `mounted.host` удерживает его renderer result.
|
|
236
259
|
|
|
237
|
-
Inspection использует схемы `opetope.devtools-graph/
|
|
238
|
-
`opetope.runtime-activity/1` (D266). В пределах одной session
|
|
260
|
+
Inspection использует схемы `opetope.devtools-graph/5` и `opetope.devtools-frame/4`, а также optional snapshots
|
|
261
|
+
`opetope.runtime-activity/1` (D266, D275). В пределах одной session
|
|
239
262
|
frame без `activity` сохраняет предыдущую activity; полный snapshot/reset без этого поля очищает наблюдение (D216).
|
|
240
263
|
Frame с `activity` заменяет предыдущую activity целиком.
|
|
241
|
-
Используйте согласованные версии runtime/devtools:
|
|
264
|
+
Используйте согласованные версии runtime/devtools: предыдущие ревизии графа и кадров отвергаются; presence слабого ребра требует graph `/5` и frame `/4`. Activity указывает execution,
|
|
242
265
|
фактическое поколение feature, физические Calls, точных текущих lane blockers, зарегистрированные leases и попытки загрузок.
|
|
243
266
|
Спрос хоста и UI-модели неизвестны; у stream наблюдается state, но не физические identities загрузок. `freshness`
|
|
244
267
|
и `truncated` отличают полное live-наблюдение от усечённого или отключённого. Закрытая session имеет stale-снимок;
|
|
@@ -15,11 +15,12 @@ type CommandInvoker = Readonly<{
|
|
|
15
15
|
type CommandNotification<Output> = (inFlight: boolean, outcome?: CommandOutcome<Output>) => void;
|
|
16
16
|
/**
|
|
17
17
|
* D203: the consumer keeps a status, not a schedule. Every `run` reaches the call, and the policy the call was
|
|
18
|
-
* created with — `queue`, `latest`, `parallel`, `once`, `
|
|
18
|
+
* created with — `queue`, `latest`, `parallel`, `once`, `dedupe` — decides what happens to it. What stays
|
|
19
19
|
* local is what only this consumer knows: whether it is mounted, its own input signal, and the outcome it shows.
|
|
20
20
|
*/
|
|
21
21
|
declare class CommandHookController<Input, Output> {
|
|
22
22
|
private readonly invoker;
|
|
23
|
+
readonly handler: () => void;
|
|
23
24
|
readonly run: CommandRun<Input, Output>;
|
|
24
25
|
private inFlight;
|
|
25
26
|
private notify;
|
package/dist/command-hook.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { Call } from '@opetope/core';
|
|
2
|
+
import type { IsAny } from '@opetope/core/internal';
|
|
2
3
|
import type { CommandRun } from './command-hook-controller.js';
|
|
3
4
|
interface CommandHookStatus<Output> {
|
|
4
5
|
readonly inFlight: boolean;
|
|
5
6
|
readonly lastError: unknown | null;
|
|
6
7
|
readonly result: Output | undefined;
|
|
7
8
|
}
|
|
9
|
+
type CommandHandler<Input> = IsAny<Input> extends true ? object : [Input] extends [never] ? object : [Input] extends [void] ? {
|
|
10
|
+
readonly handler: () => void;
|
|
11
|
+
} : object;
|
|
8
12
|
type CommandHook<Input, Output> = CommandHookStatus<Output> & {
|
|
9
13
|
readonly run: CommandRun<Input, Output>;
|
|
10
|
-
}
|
|
14
|
+
} & CommandHandler<Input>;
|
|
11
15
|
declare function useCommand<Input, Output>(command: Call<Input, Output>): CommandHook<Input, Output>;
|
|
12
16
|
export { useCommand };
|
|
13
17
|
export type { CommandHook };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useState as S,useInsertionEffect as h,useLayoutEffect as f,useMemo as g,useSyncExternalStore as b,useRef as m,useCallback as w,useEffect as
|
|
1
|
+
import{useState as S,useInsertionEffect as h,useLayoutEffect as f,useMemo as g,useSyncExternalStore as b,useRef as m,useCallback as w,useEffect as K,createElement as E,Fragment as x}from"react";import{CallError as $,declarationId as H}from"@opetope/core";import{compatibleAbortReason as T,isCancellation as G,reportDetachedError as v,isCallTarget as U,isReadable as D,createAggregateError as L,createContributionTarget as W}from"@opetope/core/internal";import{C as d}from"./contribution-isolation-Bzfbt4iM.js";import{u as p,a as O,M as B,c as J}from"./contribution-frame-B1PnpOaP.js";import{b as Fe}from"./contribution-frame-B1PnpOaP.js";function C(n,e){var t;if(G(e))return{reason:e,status:"cancelled"};try{const s=(t=n==null?void 0:n.onFailure)==null?void 0:t.call(n,e);s!==void 0&&Promise.resolve(s).catch(v)}catch(s){v(s)}return{error:e,status:"failed"}}function N(n){const e=n==null?void 0:n.onSuccess,t=n==null?void 0:n.signal;return e===void 0?t===void 0?void 0:{signal:t}:t===void 0?{onSuccess:e}:{onSuccess:e,signal:t}}function Q(n,e){let t;const s=new Promise(r=>{t=r});return{input:n,options:e===void 0?void 0:{...e},promise:s,resolve:t}}function V(n,e){const t=n.resolve;n.input=void 0,n.options=void 0,n.resolve=void 0,t==null||t(e)}class j{invoker;handler=()=>{this.run(void 0)};run=((e,t)=>{if(this.notify===void 0)return Promise.resolve({reason:new d("inactive","Command consumer is not mounted."),status:"cancelled"});const s=this.cancelledInput(t);if(s!==void 0)return Promise.resolve(s);const r=Q(e,t);return this.start(r),r.promise});inFlight=0;notify;constructor(e){this.invoker=e}attach(e){return this.notify=e,()=>{this.notify===e&&(this.notify=void 0)}}synchronize(){var e;(e=this.notify)==null||e.call(this,this.inFlight>0)}aborted(e){return{reason:new $("cancelled","Command input was cancelled.",T(e)),status:"cancelled"}}cancelledInput(e){var t;return((t=e==null?void 0:e.signal)==null?void 0:t.aborted)===!0?this.aborted(e.signal):void 0}finish(e,t){var s;e.resolve!==void 0&&(this.inFlight-=1,V(e,t),(s=this.notify)==null||s.call(this,this.inFlight>0,t))}invoke(e){let t;try{t=this.invoker.run(e.input,N(e.options)),e.input=void 0}catch(s){this.finish(e,C(e.options,s));return}t.then(s=>this.finish(e,{status:"ok",value:s}),s=>this.finish(e,C(e.options,s)))}start(e){var t;this.inFlight+=1,(t=this.notify)==null||t.call(this,!0),this.invoke(e)}}const X={inFlight:!1,lastError:null,result:void 0};function Y(n,e,t,s){return s===void 0&&n.slot===e&&n.inFlight===t}function Z(n,e,t,s){if(Y(n,e,t,s))return n;const{lastError:r,result:i}=n.slot===e?n:{lastError:null,result:void 0};return(s==null?void 0:s.status)==="ok"?{inFlight:t,lastError:null,result:s.value,slot:e}:(s==null?void 0:s.status)==="failed"?{inFlight:t,lastError:s.error,result:i,slot:e}:{inFlight:t,lastError:r,result:i,slot:e}}function _(n){const[e]=S(()=>new WeakMap);let t=e.get(n);return t===void 0&&(t=new j(n),e.set(n,t)),t}function q(n){const t=p().commandRecords.get(n);if(t===void 0)throw new d("missing",`Command ${n.id} is not bound in this contribution.`);const s=_(t.invoker),[r,i]=S(()=>({inFlight:!1,lastError:null,result:void 0,slot:s}));h(()=>s.attach((A,I)=>i(P=>Z(P,s,A,I))),[s]),f(()=>s.synchronize(),[s]);const{inFlight:o,lastError:c,result:l}=r.slot===s?r:X,a=s.run,u=s.handler;return g(()=>({handler:u,inFlight:o,lastError:c,result:l,run:a}),[u,o,c,l,a])}const ee=()=>{},M=()=>ee,te=()=>0,ne=Object.freeze({});function se(n){const e=new j(n);return{detach:void 0,hook:{handler:e.handler,inFlight:!1,lastError:null,result:void 0,run:e.run},invoker:n,slot:e}}function re(n,e){return n.inFlight===e.inFlight&&Object.is(n.result,e.result)&&Object.is(n.lastError,e.lastError)}function ie(n,e){return(e==null?void 0:e.status)==="ok"?{lastError:null,result:e.value}:(e==null?void 0:e.status)==="failed"?{lastError:e.error,result:n.result}:n}function oe(n,e,t){const s=n.hook;if(t===void 0&&s.inFlight===e)return!1;const{lastError:r,result:i}=ie(s,t),o={handler:n.slot.handler,inFlight:e,lastError:r,result:i,run:s.run};return re(s,o)?!1:(n.hook=o,!0)}function le(n,e){return(n==null?void 0:n.invoker)===e?n:se(e)}class ce{entries=new Map;listeners=new Set;revision=0;close(){var e;for(const t of this.entries.values())(e=t.detach)==null||e.call(t),t.detach=void 0;this.entries.clear()}commit(e){var t;for(const[s,r]of this.entries)e.get(s)!==r&&((t=r.detach)==null||t.call(r),r.detach=void 0);this.entries=e;for(const s of e.values())s.detach??(s.detach=s.slot.attach((r,i)=>{if(oe(s,r,i)){this.revision+=1;for(const o of this.listeners)o()}}))}getSnapshot=()=>this.revision;prepare(e,t){const s=new Map;for(const r of Reflect.ownKeys(e)){if(!Object.prototype.propertyIsEnumerable.call(e,r))continue;const i=e[r],o=i===void 0?void 0:t.commandRecords.get(i);if(o===void 0)throw new d("missing",`Command at ${String(r)} is not bound in this contribution.`);s.set(r,le(this.entries.get(r),o.invoker))}return s}subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)})}function ae(n){const e=m(void 0);return Reflect.ownKeys(n).some(s=>Object.prototype.propertyIsEnumerable.call(n,s))?e.current??(e.current=new ce):void 0}function k(n){const e=p(),t=ae(n),s=(t==null?void 0:t.getSnapshot)??te;b((t==null?void 0:t.subscribe)??M,s,s);const r=t==null?void 0:t.prepare(n,e);return h(()=>()=>t==null?void 0:t.close(),[t]),h(()=>{r!==void 0&&(t==null||t.commit(r))}),f(()=>{if(r!==void 0)for(const i of r.values())i.slot.synchronize()}),r===void 0?ne:Object.fromEntries([...r].map(([i,o])=>[i,o.hook]))}function ue(n,e){if(!D(n))throw new d("binding-invalid","Model selection read requires a Readable.");if(e.has(n))return e.get(n);const t=n.getSnapshot();return e.set(n,t),t}function de(n,e){const s=n({read:(r,i)=>{const o=ue(r,e);return i===void 0?o:i(o)}});if(typeof s!="object"||s===null||Array.isArray(s))throw new d("binding-invalid","Model selection requires a record.");return Object.fromEntries(Reflect.ownKeys(s).filter(r=>Object.prototype.propertyIsEnumerable.call(s,r)).map(r=>[r,s[r]]))}function fe(n,e,t){const s=Reflect.ownKeys(e),r=Reflect.ownKeys(n.values);if(s.length!==r.length||t.size!==n.sources.size)return!1;for(const i of t)if(!n.sources.has(i))return!1;return s.every((i,o)=>r[o]===i&&Object.is(n.values[i],e[i]))}const y={commands:{},sources:new Set,values:{}};function he(n){return Object.fromEntries(Reflect.ownKeys(n).filter(e=>U(n[e])).map(e=>[e,n[e]]))}function be(n,e){let t,s,r=y;return()=>{const i=e.current;if(i===void 0)return y;if(t!==void 0&&s===i&&[...t].every(([a,u])=>Object.is(a.getSnapshot(),u)))return r;const o=new Map,c=de(a=>i(n,a),o),l=new Set(o.keys());return(t===void 0||!fe(r,c,l))&&(r={commands:he(c),sources:l,values:c}),t=o,s=i,r}}function R(n,e=[]){for(const t of n){const s=t.dispose;t.dispose=void 0;try{s==null||s()}catch(r){e.push(r)}}if(e.length===1)throw e[0];if(e.length>1)throw L(e,"Model selection sources failed to release.")}class me{enabled=!1;listeners=new Set;sources=new Set;subscriptions=new Map;close(){this.enabled=!1,this.sources=new Set,this.releaseAll()}commit(e){this.sources=e,this.enabled=!0;try{this.synchronize()}catch(t){this.releaseAll([t])}}subscribe=e=>{const t={notify:e};this.listeners.add(t);try{this.synchronize()}catch(s){this.listeners.delete(t),this.releaseAll([s])}return()=>{this.listeners.delete(t),this.listeners.size===0&&this.releaseAll()}};add(e){const t={dispose:void 0};this.subscriptions.set(e,t);const s=e.subscribe(this.notify);if(typeof s!="function")throw new TypeError("Model selection source must return a disposer.");this.subscriptions.get(e)===t?t.dispose=s:s()}notify=()=>{for(const e of[...this.listeners])this.listeners.has(e)&&e.notify()};releaseAll(e){const t=[...this.subscriptions.values()];this.subscriptions.clear(),R(t,e)}removeUnselected(){const e=[];for(const[t,s]of this.subscriptions)this.sources.has(t)||(this.subscriptions.delete(t),e.push(s));R(e)}synchronize(){this.removeUnselected();for(const e of this.sources){if(!this.enabled||this.listeners.size===0)return;this.sources.has(e)&&!this.subscriptions.has(e)&&this.add(e)}}}const pe=()=>y;function ye(n){const e=m(void 0);return n?e.current??(e.current=new me):void 0}function Se(n,e){const t=p();if(!t.models.has(n))throw new d("missing",`Model ${n.id} is not granted to this contribution.`);const s=t.models.get(n),r=ye(e!==void 0),i=m(void 0);i.current=e;const o=e!==void 0,c=g(()=>o?be(s,i):pe,[s,o]),l=b((r==null?void 0:r.subscribe)??M,c,c),a=k(l.commands);return f(()=>()=>r==null?void 0:r.close(),[r]),f(()=>r==null?void 0:r.commit(l.sources),[l,r]),e===void 0?s:Object.fromEntries(Reflect.ownKeys(l.values).map(u=>[u,Object.prototype.hasOwnProperty.call(a,u)?a[u]:l.values[u]]))}function ge(n){const e=Object.freeze([...n]);return t=>{if(t.requires!==void 0)throw new d("duplicate","Component already declares the models it requires.");return Object.defineProperty(t,"requires",{enumerable:!1,value:e}),t}}function we(n){const e=w(r=>n.subscribe(r),[n]),t=w(()=>n.getSnapshot(),[n]),s=b(e,t,t);return K(()=>n.retain(),[n]),s}const z=Object.freeze({});function F(n){return W(n,"slot")}function Ee(n){const e=H(n.id),t=new Map,s=r=>{const i=t.get(r);if(i!==void 0)return i;const o=F({id:`${e}/${r}`});return t.set(r,o),o};return Object.defineProperty(s,"id",{enumerable:!0,value:e}),Object.freeze(s)}function ve(n){const e=O(n.target.entries),t="props"in n?n.props??z:z;return e.length===0?null:e.map(s=>E(x,{key:s.id},E(B,{authority:J(s),contribution:s.value,contributionId:s.id,slotProps:t,targetId:n.target.id})))}export{d as ContributionError,ve as Slot,F as defineSlot,Ee as defineSwitchSlot,ge as requiresModels,q as useCommand,k as useCommands,Se as useModel,O as useReadable,we as useResource,Fe as useSelector};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/command-hook-controller.ts","../src/command-hook.ts","../src/idle-subscription.ts","../src/commands-hook.ts","../src/model-selection-snapshot.ts","../src/model-selection-store.ts","../src/model-hook.ts","../src/requires-models.ts","../src/resource-hook.ts","../src/slot.tsx"],"sourcesContent":["import { CallError } from '@opetope/core';\nimport { compatibleAbortReason, isCancellation, reportDetachedError } from '@opetope/core/internal';\nimport type { CallInputArgs, CallRunOptions } from '@opetope/core/internal';\n\nimport type { CommandOutcome } from './command';\nimport { ContributionError } from './errors';\n\ntype CommandRunOptions<Output> = Readonly<{\n onFailure?: (error: unknown) => PromiseLike<void> | void;\n onSuccess?: (value: Output) => PromiseLike<void> | void;\n signal?: AbortSignal;\n}>;\n\ntype CommandRun<Input, Output> = {\n (input: Input, options?: CommandRunOptions<Output>): Promise<CommandOutcome<Output>>;\n (...args: [...CallInputArgs<Input>, options?: CommandRunOptions<Output>]): Promise<CommandOutcome<Output>>;\n};\n\ntype CommandInvoker = Readonly<{\n run: (input: never, options?: CallRunOptions<unknown>) => Promise<unknown>;\n}>;\n\ntype CommandNotification<Output> = (inFlight: boolean, outcome?: CommandOutcome<Output>) => void;\n\ntype CommandRequest<Input, Output> = {\n input: Input | undefined;\n options: CommandRunOptions<Output> | undefined;\n readonly promise: Promise<CommandOutcome<Output>>;\n resolve: ((outcome: CommandOutcome<Output>) => void) | undefined;\n};\n\nfunction failureOutcome<Output>(options: CommandRunOptions<Output> | undefined, error: unknown): CommandOutcome<never> {\n if (isCancellation(error)) return { reason: error, status: 'cancelled' };\n\n try {\n const notification = options?.onFailure?.(error);\n\n if (notification !== undefined) void Promise.resolve(notification).catch(reportDetachedError);\n } catch (callbackError) {\n reportDetachedError(callbackError);\n }\n\n return { error, status: 'failed' };\n}\n\nfunction runOptions<Output>(options: CommandRunOptions<Output> | undefined): CallRunOptions<Output> | undefined {\n const onSuccess = options?.onSuccess;\n const signal = options?.signal;\n\n if (onSuccess === undefined) return signal === undefined ? undefined : { signal };\n\n return signal === undefined ? { onSuccess } : { onSuccess, signal };\n}\n\nfunction requestOf<Input, Output>(\n input: Input,\n options: CommandRunOptions<Output> | undefined,\n): CommandRequest<Input, Output> {\n let resolve!: (outcome: CommandOutcome<Output>) => void;\n const promise = new Promise<CommandOutcome<Output>>(settle => {\n resolve = settle;\n });\n\n return { input, options: options === undefined ? undefined : { ...options }, promise, resolve };\n}\n\nfunction settle<Input, Output>(request: CommandRequest<Input, Output>, outcome: CommandOutcome<Output>): void {\n const resolve = request.resolve;\n request.input = undefined;\n request.options = undefined;\n request.resolve = undefined;\n resolve?.(outcome);\n}\n\n/**\n * D203: the consumer keeps a status, not a schedule. Every `run` reaches the call, and the policy the call was\n * created with — `queue`, `latest`, `parallel`, `once`, `singleFlight` — decides what happens to it. What stays\n * local is what only this consumer knows: whether it is mounted, its own input signal, and the outcome it shows.\n */\nclass CommandHookController<Input, Output> {\n readonly run: CommandRun<Input, Output> = ((input: Input, options?: CommandRunOptions<Output>) => {\n if (this.notify === undefined) {\n return Promise.resolve({\n reason: new ContributionError('inactive', 'Command consumer is not mounted.'),\n status: 'cancelled' as const,\n });\n }\n\n const aborted = this.cancelledInput(options);\n\n if (aborted !== undefined) return Promise.resolve(aborted);\n\n const request = requestOf(input, options);\n this.start(request);\n\n return request.promise;\n }) as CommandRun<Input, Output>;\n private inFlight = 0;\n private notify: CommandNotification<Output> | undefined;\n\n constructor(private readonly invoker: CommandInvoker) {}\n\n attach(notify: CommandNotification<Output>): () => void {\n this.notify = notify;\n\n return () => {\n if (this.notify !== notify) return;\n\n this.notify = undefined;\n };\n }\n\n synchronize(): void {\n this.notify?.(this.inFlight > 0);\n }\n\n private aborted(signal: AbortSignal): CommandOutcome<never> {\n return {\n reason: new CallError('cancelled', 'Command input was cancelled.', compatibleAbortReason(signal)),\n status: 'cancelled',\n };\n }\n\n private cancelledInput(options: CommandRunOptions<Output> | undefined): CommandOutcome<never> | undefined {\n return options?.signal?.aborted === true ? this.aborted(options.signal) : undefined;\n }\n\n private finish(request: CommandRequest<Input, Output>, outcome: CommandOutcome<Output>): void {\n if (request.resolve === undefined) return;\n\n this.inFlight -= 1;\n settle(request, outcome);\n this.notify?.(this.inFlight > 0, outcome);\n }\n\n private invoke(request: CommandRequest<Input, Output>): void {\n let invocation: Promise<Output>;\n\n try {\n invocation = this.invoker.run(request.input as never, runOptions(request.options) as never) as Promise<Output>;\n request.input = undefined;\n } catch (error) {\n this.finish(request, failureOutcome(request.options, error));\n\n return;\n }\n\n void invocation.then(\n value => this.finish(request, { status: 'ok', value }),\n (error: unknown) => this.finish(request, failureOutcome(request.options, error)),\n );\n }\n\n private start(request: CommandRequest<Input, Output>): void {\n this.inFlight += 1;\n // Reserve the flight before publishing: a reentrant run must already see this consumer as busy.\n this.notify?.(true);\n this.invoke(request);\n }\n}\n\nexport { CommandHookController };\nexport type { CommandInvoker, CommandRun };\n","import { useInsertionEffect, useLayoutEffect, useMemo, useState } from 'react';\n\nimport type { Call } from '@opetope/core';\n\nimport type { CommandOutcome } from './command';\nimport { CommandHookController } from './command-hook-controller';\nimport type { CommandInvoker, CommandRun } from './command-hook-controller';\nimport { ContributionError } from './errors';\nimport { useFrame } from './mount-context';\n\ninterface CommandHookStatus<Output> {\n readonly inFlight: boolean;\n readonly lastError: unknown | null;\n readonly result: Output | undefined;\n}\n\nconst emptyStatus: CommandHookStatus<never> = { inFlight: false, lastError: null, result: undefined };\n\ntype CommandHook<Input, Output> = CommandHookStatus<Output> & { readonly run: CommandRun<Input, Output> };\n\ntype CommandHookState<Input, Output> = CommandHookStatus<Output> & {\n readonly slot: CommandHookController<Input, Output>;\n};\n\nfunction unchangedState<Input, Output>(\n current: CommandHookState<Input, Output>,\n slot: CommandHookController<Input, Output>,\n inFlight: boolean,\n outcome: CommandOutcome<Output> | undefined,\n): boolean {\n return outcome === undefined && current.slot === slot && current.inFlight === inFlight;\n}\n\nfunction nextState<Input, Output>(\n current: CommandHookState<Input, Output>,\n slot: CommandHookController<Input, Output>,\n inFlight: boolean,\n outcome?: CommandOutcome<Output>,\n): CommandHookState<Input, Output> {\n if (unchangedState(current, slot, inFlight, outcome)) return current;\n\n const { lastError, result } = current.slot === slot ? current : { lastError: null, result: undefined };\n\n if (outcome?.status === 'ok') return { inFlight, lastError: null, result: outcome.value, slot };\n\n if (outcome?.status === 'failed') return { inFlight, lastError: outcome.error, result, slot };\n\n return { inFlight, lastError, result, slot };\n}\n\nfunction useCommandSlot<Input, Output>(invoker: CommandInvoker): CommandHookController<Input, Output> {\n // Slots are inert until commit. An interrupted render cannot fence the committed source or admit its own work.\n const [slots] = useState(() => new WeakMap<object, CommandHookController<Input, Output>>());\n let slot = slots.get(invoker);\n\n if (slot === undefined) {\n slot = new CommandHookController(invoker);\n slots.set(invoker, slot);\n }\n\n return slot;\n}\n\nfunction useCommand<Input, Output>(command: Call<Input, Output>): CommandHook<Input, Output> {\n const frame = useFrame();\n const record = frame.commandRecords.get(command);\n\n if (record === undefined) {\n throw new ContributionError('missing', `Command ${command.id} is not bound in this contribution.`);\n }\n\n const currentSlot = useCommandSlot<Input, Output>(record.invoker);\n const [hookState, setHookState] = useState<CommandHookState<Input, Output>>(() => ({\n inFlight: false,\n lastError: null,\n result: undefined,\n slot: currentSlot,\n }));\n useInsertionEffect(\n () =>\n currentSlot.attach((inFlight, outcome) =>\n setHookState(current => nextState(current, currentSlot, inFlight, outcome)),\n ),\n [currentSlot],\n );\n useLayoutEffect(() => currentSlot.synchronize(), [currentSlot]);\n const { inFlight, lastError, result } = hookState.slot === currentSlot ? hookState : emptyStatus;\n const run = currentSlot.run;\n\n return useMemo(() => ({ inFlight, lastError, result, run }), [inFlight, lastError, result, run]);\n}\n\nexport { useCommand };\nexport type { CommandHook };\n","const idleRelease = (): void => undefined;\nconst subscribeIdle = (): (() => void) => idleRelease;\nconst idleRevision = (): number => 0;\n\nexport { idleRevision, subscribeIdle };\n","import { useInsertionEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';\n\nimport type { Call } from '@opetope/core';\n\nimport type { CommandOutcome } from './command';\nimport type { CommandHook } from './command-hook';\nimport { CommandHookController } from './command-hook-controller';\nimport type { CommandInvoker } from './command-hook-controller';\nimport { ContributionError } from './errors';\nimport { idleRevision, subscribeIdle } from './idle-subscription';\nimport { useFrame } from './mount-context';\nimport type { Frame } from './mount-frame';\n\ntype CommandSelection = Readonly<Record<string, Call<never, unknown>>>;\ntype HookOf<Command> = Command extends Call<infer Input, infer Output> ? CommandHook<Input, Output> : never;\ntype CommandsHook<Commands> = {\n readonly [Key in keyof Commands]: HookOf<Commands[Key]>;\n};\nconst emptyHooks = Object.freeze({});\n\ntype CommandEntry = {\n detach: (() => void) | undefined;\n hook: CommandHook<never, unknown>;\n readonly invoker: CommandInvoker;\n readonly slot: CommandHookController<never, unknown>;\n};\n\nfunction createEntry(invoker: CommandInvoker): CommandEntry {\n const slot = new CommandHookController<never, unknown>(invoker);\n\n return {\n detach: undefined,\n hook: { inFlight: false, lastError: null, result: undefined, run: slot.run },\n invoker,\n slot,\n };\n}\n\nfunction unchangedHook(previous: CommandHook<never, unknown>, next: CommandHook<never, unknown>): boolean {\n return (\n previous.inFlight === next.inFlight &&\n Object.is(previous.result, next.result) &&\n Object.is(previous.lastError, next.lastError)\n );\n}\n\nfunction outcomeStatus(previous: CommandHook<never, unknown>, outcome: CommandOutcome<unknown> | undefined) {\n if (outcome?.status === 'ok') return { lastError: null, result: outcome.value };\n\n if (outcome?.status === 'failed') return { lastError: outcome.error, result: previous.result };\n\n return previous;\n}\n\nfunction updateEntry(entry: CommandEntry, inFlight: boolean, outcome?: CommandOutcome<unknown>): boolean {\n const previous = entry.hook;\n\n if (outcome === undefined && previous.inFlight === inFlight) return false;\n\n const { lastError, result } = outcomeStatus(previous, outcome);\n const next = { inFlight, lastError, result, run: previous.run };\n\n if (unchangedHook(previous, next)) return false;\n\n entry.hook = next;\n\n return true;\n}\n\nfunction selectEntry(previous: CommandEntry | undefined, invoker: CommandInvoker): CommandEntry {\n return previous?.invoker === invoker ? previous : createEntry(invoker);\n}\n\n/** Selection is inert during render; only a committed selection can admit work or discard an old queue. */\nclass CommandGroup {\n private entries = new Map<PropertyKey, CommandEntry>();\n private readonly listeners = new Set<() => void>();\n private revision = 0;\n\n close(): void {\n for (const entry of this.entries.values()) {\n entry.detach?.();\n entry.detach = undefined;\n }\n\n this.entries.clear();\n }\n\n commit(selected: Map<PropertyKey, CommandEntry>): void {\n for (const [key, entry] of this.entries) {\n if (selected.get(key) === entry) continue;\n\n entry.detach?.();\n entry.detach = undefined;\n }\n\n this.entries = selected;\n\n for (const entry of selected.values()) {\n entry.detach ??= entry.slot.attach((inFlight, outcome) => {\n if (!updateEntry(entry, inFlight, outcome)) return;\n\n this.revision += 1;\n\n for (const listener of this.listeners) listener();\n });\n }\n }\n\n getSnapshot = (): number => this.revision;\n\n prepare(commands: CommandSelection, frame: Frame): Map<PropertyKey, CommandEntry> {\n const selected = new Map<PropertyKey, CommandEntry>();\n\n for (const key of Reflect.ownKeys(commands)) {\n if (!Object.prototype.propertyIsEnumerable.call(commands, key)) continue;\n\n const command = (commands as Readonly<Record<PropertyKey, Call<never, unknown>>>)[key];\n const record = command === undefined ? undefined : frame.commandRecords.get(command);\n\n if (record === undefined) {\n throw new ContributionError('missing', `Command at ${String(key)} is not bound in this contribution.`);\n }\n\n selected.set(key, selectEntry(this.entries.get(key), record.invoker));\n }\n\n return selected;\n }\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n };\n}\n\nfunction useCommandGroup(commands: CommandSelection): CommandGroup | undefined {\n const groupRef = useRef<CommandGroup | undefined>(undefined);\n const populated = Reflect.ownKeys(commands).some(key => Object.prototype.propertyIsEnumerable.call(commands, key));\n\n return populated ? (groupRef.current ??= new CommandGroup()) : undefined;\n}\n\nfunction useCommands<Commands extends { readonly [Key in keyof Commands]: Call<never, unknown> }>(\n commands: Commands,\n): CommandsHook<Commands> {\n const frame = useFrame();\n const group = useCommandGroup(commands);\n const getSnapshot = group?.getSnapshot ?? idleRevision;\n useSyncExternalStore(group?.subscribe ?? subscribeIdle, getSnapshot, getSnapshot);\n const selected = group?.prepare(commands, frame);\n useInsertionEffect(() => () => group?.close(), [group]);\n useInsertionEffect(() => {\n if (selected !== undefined) group?.commit(selected);\n });\n useLayoutEffect(() => {\n if (selected === undefined) return;\n\n for (const entry of selected.values()) entry.slot.synchronize();\n });\n\n return (\n selected === undefined ? emptyHooks : Object.fromEntries([...selected].map(([key, entry]) => [key, entry.hook]))\n ) as CommandsHook<Commands>;\n}\n\nexport { useCommands };\n","import type { Readable } from '@opetope/core';\nimport { isCallTarget, isReadable } from '@opetope/core/internal';\n\nimport { ContributionError } from './errors';\nimport type { AnyCommand } from './model-binding';\n\ninterface SelectionRead {\n <Value>(source: Readable<Value>): Value;\n <Value, Selected>(source: Readable<Value>, select: (value: Value) => Selected): Selected;\n}\n\ntype SelectionContext = Readonly<{ read: SelectionRead }>;\ntype NonSelectionRecord =\n | readonly unknown[]\n | ((...arguments_: never[]) => unknown)\n | (abstract new (...arguments_: never[]) => unknown)\n | Date\n | PromiseLike<unknown>\n | ReadonlyMap<unknown, unknown>\n | ReadonlySet<unknown>\n | RegExp\n | WeakMap<object, unknown>\n | WeakSet<object>;\n/** A named interface needs no open index signature; container and callable results are not field selections. */\ntype SelectionShape<Selected extends object> = Selected extends NonSelectionRecord ? never : Selected;\ntype SelectionRecord = Readonly<Record<PropertyKey, unknown>>;\ntype SelectionSnapshot = Readonly<{\n commands: Readonly<Record<PropertyKey, AnyCommand>>;\n sources: ReadonlySet<Readable<unknown>>;\n values: SelectionRecord;\n}>;\n\nfunction readSource<Value>(source: Readable<Value>, sources: Map<Readable<unknown>, unknown>): Value {\n if (!isReadable(source)) {\n throw new ContributionError('binding-invalid', 'Model selection read requires a Readable.');\n }\n\n if (sources.has(source)) return sources.get(source) as Value;\n\n const value = source.getSnapshot();\n sources.set(source, value);\n\n return value;\n}\n\nfunction collectSelection(\n select: (context: SelectionContext) => object,\n sources: Map<Readable<unknown>, unknown>,\n): SelectionRecord {\n const read = <Value, Selected>(source: Readable<Value>, project?: (value: Value) => Selected) => {\n const value = readSource(source, sources);\n\n return project === undefined ? value : project(value);\n };\n const selected = select({ read });\n\n if (typeof selected !== 'object' || selected === null || Array.isArray(selected)) {\n throw new ContributionError('binding-invalid', 'Model selection requires a record.');\n }\n\n return Object.fromEntries(\n Reflect.ownKeys(selected)\n .filter(key => Object.prototype.propertyIsEnumerable.call(selected, key))\n .map(key => [key, (selected as SelectionRecord)[key]]),\n );\n}\n\nfunction equalSelection(previous: SelectionSnapshot, values: SelectionRecord, sources: ReadonlySet<Readable<unknown>>) {\n const keys = Reflect.ownKeys(values);\n const previousKeys = Reflect.ownKeys(previous.values);\n\n if (keys.length !== previousKeys.length || sources.size !== previous.sources.size) return false;\n\n for (const source of sources) if (!previous.sources.has(source)) return false;\n\n return keys.every((key, index) => previousKeys[index] === key && Object.is(previous.values[key], values[key]));\n}\n\ntype ModelSelector<Model> = (model: Model, context: SelectionContext) => object;\ntype SelectionReaderRef<Model> = { readonly current: ModelSelector<Model> | undefined };\n\nconst emptySelectionSnapshot: SelectionSnapshot = { commands: {}, sources: new Set(), values: {} };\n\nfunction selectionCommands(values: SelectionRecord): Readonly<Record<PropertyKey, AnyCommand>> {\n return Object.fromEntries(\n Reflect.ownKeys(values)\n .filter(key => isCallTarget(values[key]))\n .map(key => [key, values[key]]),\n ) as Readonly<Record<PropertyKey, AnyCommand>>;\n}\n\n/**\n * D214: one reader per model, not per render. The author's selector arrives through a ref, so an inline arrow does not\n * rebuild the reader; the fast path — nothing observed has moved — belongs to the selector that computed the snapshot,\n * so a new selector is always called again, its result compared field by field, and an equal selection keeps the\n * previous snapshot. A rejected or abandoned render still changes nothing: only a committed selection subscribes.\n */\nfunction createSelectionSnapshot<Model>(model: Model, selectRef: SelectionReaderRef<Model>): () => SelectionSnapshot {\n let observed: Map<Readable<unknown>, unknown> | undefined;\n let observedSelect: ModelSelector<Model> | undefined;\n let snapshot: SelectionSnapshot = emptySelectionSnapshot;\n\n return () => {\n const select = selectRef.current;\n\n if (select === undefined) return emptySelectionSnapshot;\n\n if (\n observed !== undefined &&\n observedSelect === select &&\n [...observed].every(([source, value]) => Object.is(source.getSnapshot(), value))\n ) {\n return snapshot;\n }\n\n const nextObserved = new Map<Readable<unknown>, unknown>();\n const values = collectSelection(context => select(model, context), nextObserved);\n const sources = new Set(nextObserved.keys());\n\n if (observed === undefined || !equalSelection(snapshot, values, sources)) {\n snapshot = { commands: selectionCommands(values), sources, values };\n }\n\n observed = nextObserved;\n observedSelect = select;\n\n return snapshot;\n };\n}\n\nexport { createSelectionSnapshot, emptySelectionSnapshot };\nexport type { ModelSelector, SelectionContext, SelectionShape };\n","import type { Readable } from '@opetope/core';\nimport { createAggregateError } from '@opetope/core/internal';\n\ntype Subscription = { dispose: (() => void) | undefined };\ntype Listener = Readonly<{ notify: () => void }>;\n\nfunction releaseSubscriptions(subscriptions: Iterable<Subscription>, failures: unknown[] = []): void {\n for (const subscription of subscriptions) {\n const dispose = subscription.dispose;\n subscription.dispose = undefined;\n\n try {\n dispose?.();\n } catch (error) {\n failures.push(error);\n }\n }\n\n if (failures.length === 1) throw failures[0];\n\n if (failures.length > 1) throw createAggregateError(failures, 'Model selection sources failed to release.');\n}\n\n/** A subscription set, not a scheduler: source notifications use React's snapshot consistency check. */\nclass ModelSelectionStore {\n private enabled = false;\n private readonly listeners = new Set<Listener>();\n private sources: ReadonlySet<Readable<unknown>> = new Set();\n private readonly subscriptions = new Map<Readable<unknown>, Subscription>();\n\n close(): void {\n this.enabled = false;\n this.sources = new Set();\n this.releaseAll();\n }\n\n commit(sources: ReadonlySet<Readable<unknown>>): void {\n this.sources = sources;\n this.enabled = true;\n\n try {\n this.synchronize();\n } catch (error) {\n this.releaseAll([error]);\n }\n }\n\n subscribe = (notify: () => void): (() => void) => {\n const listener = { notify };\n this.listeners.add(listener);\n\n try {\n this.synchronize();\n } catch (error) {\n this.listeners.delete(listener);\n this.releaseAll([error]);\n }\n\n return () => {\n this.listeners.delete(listener);\n\n if (this.listeners.size === 0) this.releaseAll();\n };\n };\n\n private add(source: Readable<unknown>): void {\n const subscription: Subscription = { dispose: undefined };\n // Reserve before foreign code: a synchronous notification may replace or close this selection.\n this.subscriptions.set(source, subscription);\n const dispose = source.subscribe(this.notify);\n\n if (typeof dispose !== 'function') throw new TypeError('Model selection source must return a disposer.');\n\n if (this.subscriptions.get(source) === subscription) subscription.dispose = dispose;\n else dispose();\n }\n\n private notify = (): void => {\n for (const listener of [...this.listeners]) {\n if (this.listeners.has(listener)) listener.notify();\n }\n };\n\n private releaseAll(failures?: unknown[]): void {\n const subscriptions = [...this.subscriptions.values()];\n this.subscriptions.clear();\n releaseSubscriptions(subscriptions, failures);\n }\n\n private removeUnselected(): void {\n const removed: Subscription[] = [];\n\n for (const [source, subscription] of this.subscriptions) {\n if (this.sources.has(source)) continue;\n\n this.subscriptions.delete(source);\n removed.push(subscription);\n }\n\n releaseSubscriptions(removed);\n }\n\n private synchronize(): void {\n this.removeUnselected();\n\n for (const source of this.sources) {\n if (!this.enabled || this.listeners.size === 0) return;\n\n if (this.sources.has(source) && !this.subscriptions.has(source)) this.add(source);\n }\n }\n}\n\nexport { ModelSelectionStore };\n","import { useLayoutEffect, useMemo, useRef, useSyncExternalStore } from 'react';\n\nimport type { Call, ModelOf } from '@opetope/core';\n\nimport type { CommandHook } from './command-hook';\nimport { useCommands } from './commands-hook';\nimport { ContributionError } from './errors';\nimport { subscribeIdle } from './idle-subscription';\nimport type { AnyModel } from './model-binding';\nimport { createSelectionSnapshot, emptySelectionSnapshot } from './model-selection-snapshot';\nimport type { ModelSelector, SelectionContext, SelectionShape } from './model-selection-snapshot';\nimport { ModelSelectionStore } from './model-selection-store';\nimport { useFrame } from './mount-context';\n\ntype SelectedValue<Value> = Value extends Call<infer Input, infer Output> ? CommandHook<Input, Output> : Value;\ntype ModelSelection<Selected> = { readonly [Key in keyof Selected]: SelectedValue<Selected[Key]> };\n\nconst readEmptySnapshot = () => emptySelectionSnapshot;\n\nfunction useSelectionStore(selected: boolean): ModelSelectionStore | undefined {\n const storeRef = useRef<ModelSelectionStore | undefined>(undefined);\n\n return selected ? (storeRef.current ??= new ModelSelectionStore()) : undefined;\n}\n\n/** D205: resolve only a granted model, explicitly read data, and reuse the ordinary per-key command consumers. */\nfunction useModel<Declaration extends AnyModel>(declaration: Declaration): ModelOf<Declaration>;\nfunction useModel<Declaration extends AnyModel, const Selected extends object>(\n declaration: Declaration,\n select: (model: ModelOf<Declaration>, context: SelectionContext) => Selected & SelectionShape<Selected>,\n): ModelSelection<Selected>;\nfunction useModel<Declaration extends AnyModel>(\n declaration: Declaration,\n select?: (model: ModelOf<Declaration>, context: SelectionContext) => object,\n): unknown {\n const frame = useFrame();\n\n if (!frame.models.has(declaration)) {\n throw new ContributionError('missing', `Model ${declaration.id} is not granted to this contribution.`);\n }\n\n const model = frame.models.get(declaration) as ModelOf<Declaration>;\n const store = useSelectionStore(select !== undefined);\n // D214: the selector of this render, read by a reader that belongs to the model. Writing the latest callback into\n // a ref is what `useSyncExternalStoreWithSelector` does: the reader only reads it, and never writes to it.\n const selectRef = useRef<ModelSelector<ModelOf<Declaration>> | undefined>(undefined);\n selectRef.current = select;\n const selected = select !== undefined;\n const getSnapshot = useMemo(\n () => (selected ? createSelectionSnapshot(model, selectRef) : readEmptySnapshot),\n [model, selected],\n );\n const snapshot = useSyncExternalStore(store?.subscribe ?? subscribeIdle, getSnapshot, getSnapshot);\n const commands = useCommands(snapshot.commands);\n useLayoutEffect(() => () => store?.close(), [store]);\n useLayoutEffect(() => store?.commit(snapshot.sources), [snapshot, store]);\n\n if (select === undefined) return model;\n\n return Object.fromEntries(\n Reflect.ownKeys(snapshot.values).map(key => [\n key,\n Object.prototype.hasOwnProperty.call(commands, key) ? commands[key] : snapshot.values[key],\n ]),\n );\n}\n\nexport { useModel };\n","import type { FunctionComponent } from 'react';\n\nimport type { ModelIdentity } from '@opetope/core/internal';\n\nimport { ContributionError } from './errors';\n\ntype AnyModel = ModelIdentity;\n\n/**\n * The marker a component uses to state which UI models of its contribution it reads. `slot` checks by type that the\n * contribution grants every model of this list — it may grant more, because the mount serves its whole instance.\n *\n * The runtime authority is the mount frame, not this marker: `useModel` resolves against what the mount was given\n * and refuses anything else. The lint rule `opetope/require-declared-models` checks visible contribution sites and\n * each reader of a per-mount model within the same module. Imported implementations and dynamic declaration lists\n * remain unknown to this syntactic check (D85, D158, D250).\n */\ntype ComponentRequiringModels<Props, Models extends readonly AnyModel[]> = FunctionComponent<Props> & {\n readonly requires: Models;\n};\n\nfunction requiresModels<const Models extends readonly AnyModel[]>(\n models: Models,\n): <Props>(component: FunctionComponent<Props>) => ComponentRequiringModels<Props, Models> {\n const declared = Object.freeze([...models]) as unknown as Models;\n\n return <Props>(component: FunctionComponent<Props>): ComponentRequiringModels<Props, Models> => {\n const existing = (component as { readonly requires?: readonly AnyModel[] }).requires;\n\n if (existing !== undefined) {\n throw new ContributionError('duplicate', 'Component already declares the models it requires.');\n }\n\n Object.defineProperty(component, 'requires', { enumerable: false, value: declared });\n\n return component as ComponentRequiringModels<Props, Models>;\n };\n}\n\nexport { requiresModels };\n","import { useCallback, useEffect, useSyncExternalStore } from 'react';\n\nimport type { Resource, ResourceSnapshot } from '@opetope/runtime';\nimport type { ResourceRequestKey } from '@opetope/runtime/internal';\n\nfunction useResource<Data, Key extends ResourceRequestKey>(resource: Resource<Data, Key>): ResourceSnapshot<Data, Key> {\n const subscribe = useCallback((listener: () => void) => resource.subscribe(listener), [resource]);\n // D199: a resource is a structural contract, so it may be an object with methods. Reading through it keeps the\n // receiver the adapter expects; handing `resource.getSnapshot` to React would call it with none.\n const getSnapshot = useCallback(() => resource.getSnapshot(), [resource]);\n const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n useEffect(() => resource.retain(), [resource]);\n\n return snapshot;\n}\n\nexport { useResource };\n","import type { ComponentType, ReactNode } from 'react';\nimport { createElement, Fragment } from 'react';\n\nimport type { DeclarationId } from '@opetope/core';\nimport { declarationId } from '@opetope/core';\nimport type { ContributionTarget } from '@opetope/core/internal';\nimport { createContributionTarget } from '@opetope/core/internal';\nimport type { ContributionModel } from '@opetope/runtime/internal';\n\nimport { contributionAuthority, ContributionMount } from './contribution-frame';\nimport { useReadable } from './readable-hooks';\n\ntype SlotProperties = object | undefined;\ntype EmptySlotProperties = Readonly<Record<string, never>>;\ntype SlotComponentProperties<Props extends SlotProperties> = [Props] extends [undefined]\n ? EmptySlotProperties\n : Extract<Props, object>;\n\n/**\n * What a contribution publishes: the component, the optional props adapter and the optional UI models the mount\n * creates. Without an adapter the component takes the slot props; with one it takes exactly the adapter result (D85).\n */\ntype SlotContribution<Props extends SlotProperties = undefined> = {\n readonly Component: ComponentType<never>;\n readonly models?: readonly ContributionModel[];\n readonly props?: (slotProps: SlotComponentProperties<Props>) => object;\n};\n\ntype SlotTarget<Props extends SlotProperties = undefined> = ContributionTarget<SlotContribution<Props>>;\n\ntype SwitchSlotTarget<Route extends string, Props extends SlotProperties = undefined> = ((\n route: Route,\n) => SlotTarget<Props>) & {\n readonly id: DeclarationId;\n};\n\ntype SlotRenderProps<Props extends SlotProperties> = [Props] extends [undefined]\n ? {\n readonly props?: never;\n readonly target: SlotTarget<Props>;\n }\n : {\n readonly props: SlotComponentProperties<Props>;\n readonly target: SlotTarget<Props>;\n };\n\nconst emptySlotProperties: EmptySlotProperties = Object.freeze({});\n\nfunction defineSlot<Props extends SlotProperties = undefined>(options: { readonly id: string }): SlotTarget<Props> {\n return createContributionTarget<SlotContribution<Props>>(options, 'slot');\n}\n\nfunction defineSwitchSlot<Route extends string, Props extends SlotProperties = undefined>(options: {\n readonly id: string;\n}): SwitchSlotTarget<Route, Props> {\n const id = declarationId(options.id);\n const targets = new Map<Route, SlotTarget<Props>>();\n\n const switchSlot = (route: Route): SlotTarget<Props> => {\n const existing = targets.get(route);\n\n if (existing !== undefined) return existing;\n\n const target = defineSlot<Props>({ id: `${id}/${route}` });\n targets.set(route, target);\n\n return target;\n };\n\n Object.defineProperty(switchSlot, 'id', { enumerable: true, value: id });\n\n return Object.freeze(switchSlot) as SwitchSlotTarget<Route, Props>;\n}\n\n/**\n * Every contribution renders inside its own mount: the models its generation owns plus the UI models it declared,\n * created on mount and closed on unmount (D70, D85).\n */\nfunction Slot<Props extends SlotProperties>(options: SlotRenderProps<Props>): ReactNode {\n const entries = useReadable(options.target.entries);\n const slotProps: object = 'props' in options ? (options.props ?? emptySlotProperties) : emptySlotProperties;\n\n if (entries.length === 0) return null;\n\n return entries.map(entry =>\n createElement(\n Fragment,\n { key: entry.id },\n createElement(ContributionMount, {\n authority: contributionAuthority(entry),\n contribution: entry.value,\n contributionId: entry.id,\n slotProps,\n targetId: options.target.id,\n }),\n ),\n );\n}\n\nexport { defineSlot, defineSwitchSlot, Slot };\nexport type { SlotComponentProperties, SlotContribution, SlotProperties, SlotTarget, SwitchSlotTarget };\n"],"names":["failureOutcome","options","error","isCancellation","notification","_a","reportDetachedError","callbackError","runOptions","onSuccess","signal","requestOf","input","resolve","promise","settle","request","outcome","CommandHookController","ContributionError","aborted","invoker","notify","CallError","compatibleAbortReason","invocation","value","emptyStatus","unchangedState","current","slot","inFlight","nextState","lastError","result","useCommandSlot","slots","useState","useCommand","command","record","useFrame","currentSlot","hookState","setHookState","useInsertionEffect","useLayoutEffect","run","useMemo","idleRelease","subscribeIdle","idleRevision","emptyHooks","createEntry","unchangedHook","previous","next","outcomeStatus","updateEntry","entry","selectEntry","CommandGroup","selected","key","listener","commands","frame","useCommandGroup","groupRef","useRef","useCommands","group","getSnapshot","useSyncExternalStore","readSource","source","sources","isReadable","collectSelection","select","project","equalSelection","values","keys","previousKeys","index","emptySelectionSnapshot","selectionCommands","isCallTarget","createSelectionSnapshot","model","selectRef","observed","observedSelect","snapshot","nextObserved","context","releaseSubscriptions","subscriptions","failures","subscription","dispose","createAggregateError","ModelSelectionStore","removed","readEmptySnapshot","useSelectionStore","storeRef","useModel","declaration","store","requiresModels","models","declared","component","useResource","resource","subscribe","useCallback","useEffect","emptySlotProperties","defineSlot","createContributionTarget","defineSwitchSlot","id","declarationId","targets","switchSlot","route","existing","target","Slot","entries","useReadable","slotProps","createElement","Fragment","ContributionMount","contributionAuthority"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/command-hook-controller.ts","../src/command-hook.ts","../src/idle-subscription.ts","../src/commands-hook.ts","../src/model-selection-snapshot.ts","../src/model-selection-store.ts","../src/model-hook.ts","../src/requires-models.ts","../src/resource-hook.ts","../src/slot.tsx"],"sourcesContent":["import { CallError } from '@opetope/core';\nimport { compatibleAbortReason, isCancellation, reportDetachedError } from '@opetope/core/internal';\nimport type { CallInputArgs, CallRunOptions } from '@opetope/core/internal';\n\nimport type { CommandOutcome } from './command';\nimport { ContributionError } from './errors';\n\ntype CommandRunOptions<Output> = Readonly<{\n onFailure?: (error: unknown) => PromiseLike<void> | void;\n onSuccess?: (value: Output) => PromiseLike<void> | void;\n signal?: AbortSignal;\n}>;\n\ntype CommandRun<Input, Output> = {\n (input: Input, options?: CommandRunOptions<Output>): Promise<CommandOutcome<Output>>;\n (...args: [...CallInputArgs<Input>, options?: CommandRunOptions<Output>]): Promise<CommandOutcome<Output>>;\n};\n\ntype CommandInvoker = Readonly<{\n run: (input: never, options?: CallRunOptions<unknown>) => Promise<unknown>;\n}>;\n\ntype CommandNotification<Output> = (inFlight: boolean, outcome?: CommandOutcome<Output>) => void;\n\ntype CommandRequest<Input, Output> = {\n input: Input | undefined;\n options: CommandRunOptions<Output> | undefined;\n readonly promise: Promise<CommandOutcome<Output>>;\n resolve: ((outcome: CommandOutcome<Output>) => void) | undefined;\n};\n\nfunction failureOutcome<Output>(options: CommandRunOptions<Output> | undefined, error: unknown): CommandOutcome<never> {\n if (isCancellation(error)) return { reason: error, status: 'cancelled' };\n\n try {\n const notification = options?.onFailure?.(error);\n\n if (notification !== undefined) void Promise.resolve(notification).catch(reportDetachedError);\n } catch (callbackError) {\n reportDetachedError(callbackError);\n }\n\n return { error, status: 'failed' };\n}\n\nfunction runOptions<Output>(options: CommandRunOptions<Output> | undefined): CallRunOptions<Output> | undefined {\n const onSuccess = options?.onSuccess;\n const signal = options?.signal;\n\n if (onSuccess === undefined) return signal === undefined ? undefined : { signal };\n\n return signal === undefined ? { onSuccess } : { onSuccess, signal };\n}\n\nfunction requestOf<Input, Output>(\n input: Input,\n options: CommandRunOptions<Output> | undefined,\n): CommandRequest<Input, Output> {\n let resolve!: (outcome: CommandOutcome<Output>) => void;\n const promise = new Promise<CommandOutcome<Output>>(settle => {\n resolve = settle;\n });\n\n return { input, options: options === undefined ? undefined : { ...options }, promise, resolve };\n}\n\nfunction settle<Input, Output>(request: CommandRequest<Input, Output>, outcome: CommandOutcome<Output>): void {\n const resolve = request.resolve;\n request.input = undefined;\n request.options = undefined;\n request.resolve = undefined;\n resolve?.(outcome);\n}\n\n/**\n * D203: the consumer keeps a status, not a schedule. Every `run` reaches the call, and the policy the call was\n * created with — `queue`, `latest`, `parallel`, `once`, `dedupe` — decides what happens to it. What stays\n * local is what only this consumer knows: whether it is mounted, its own input signal, and the outcome it shows.\n */\nclass CommandHookController<Input, Output> {\n // React may supply an event; inputless handlers intentionally never forward it as Call data.\n readonly handler = (): void => {\n void this.run(undefined as Input);\n };\n readonly run: CommandRun<Input, Output> = ((input: Input, options?: CommandRunOptions<Output>) => {\n if (this.notify === undefined) {\n return Promise.resolve({\n reason: new ContributionError('inactive', 'Command consumer is not mounted.'),\n status: 'cancelled' as const,\n });\n }\n\n const aborted = this.cancelledInput(options);\n\n if (aborted !== undefined) return Promise.resolve(aborted);\n\n const request = requestOf(input, options);\n this.start(request);\n\n return request.promise;\n }) as CommandRun<Input, Output>;\n private inFlight = 0;\n private notify: CommandNotification<Output> | undefined;\n\n constructor(private readonly invoker: CommandInvoker) {}\n\n attach(notify: CommandNotification<Output>): () => void {\n this.notify = notify;\n\n return () => {\n if (this.notify !== notify) return;\n\n this.notify = undefined;\n };\n }\n\n synchronize(): void {\n this.notify?.(this.inFlight > 0);\n }\n\n private aborted(signal: AbortSignal): CommandOutcome<never> {\n return {\n reason: new CallError('cancelled', 'Command input was cancelled.', compatibleAbortReason(signal)),\n status: 'cancelled',\n };\n }\n\n private cancelledInput(options: CommandRunOptions<Output> | undefined): CommandOutcome<never> | undefined {\n return options?.signal?.aborted === true ? this.aborted(options.signal) : undefined;\n }\n\n private finish(request: CommandRequest<Input, Output>, outcome: CommandOutcome<Output>): void {\n if (request.resolve === undefined) return;\n\n this.inFlight -= 1;\n settle(request, outcome);\n this.notify?.(this.inFlight > 0, outcome);\n }\n\n private invoke(request: CommandRequest<Input, Output>): void {\n let invocation: Promise<Output>;\n\n try {\n invocation = this.invoker.run(request.input as never, runOptions(request.options) as never) as Promise<Output>;\n request.input = undefined;\n } catch (error) {\n this.finish(request, failureOutcome(request.options, error));\n\n return;\n }\n\n void invocation.then(\n value => this.finish(request, { status: 'ok', value }),\n (error: unknown) => this.finish(request, failureOutcome(request.options, error)),\n );\n }\n\n private start(request: CommandRequest<Input, Output>): void {\n this.inFlight += 1;\n // Reserve the flight before publishing: a reentrant run must already see this consumer as busy.\n this.notify?.(true);\n this.invoke(request);\n }\n}\n\nexport { CommandHookController };\nexport type { CommandInvoker, CommandRun };\n","import { useInsertionEffect, useLayoutEffect, useMemo, useState } from 'react';\n\nimport type { Call } from '@opetope/core';\nimport type { IsAny } from '@opetope/core/internal';\n\nimport type { CommandOutcome } from './command';\nimport { CommandHookController } from './command-hook-controller';\nimport type { CommandInvoker, CommandRun } from './command-hook-controller';\nimport { ContributionError } from './errors';\nimport { useFrame } from './mount-context';\n\ninterface CommandHookStatus<Output> {\n readonly inFlight: boolean;\n readonly lastError: unknown | null;\n readonly result: Output | undefined;\n}\n\nconst emptyStatus: CommandHookStatus<never> = { inFlight: false, lastError: null, result: undefined };\n\ntype CommandHandler<Input> =\n IsAny<Input> extends true\n ? object\n : [Input] extends [never]\n ? object\n : [Input] extends [void]\n ? { readonly handler: () => void }\n : object;\n\ntype CommandHook<Input, Output> = CommandHookStatus<Output> & {\n readonly run: CommandRun<Input, Output>;\n} & CommandHandler<Input>;\n\ntype CommandHookState<Input, Output> = CommandHookStatus<Output> & {\n readonly slot: CommandHookController<Input, Output>;\n};\n\nfunction unchangedState<Input, Output>(\n current: CommandHookState<Input, Output>,\n slot: CommandHookController<Input, Output>,\n inFlight: boolean,\n outcome: CommandOutcome<Output> | undefined,\n): boolean {\n return outcome === undefined && current.slot === slot && current.inFlight === inFlight;\n}\n\nfunction nextState<Input, Output>(\n current: CommandHookState<Input, Output>,\n slot: CommandHookController<Input, Output>,\n inFlight: boolean,\n outcome?: CommandOutcome<Output>,\n): CommandHookState<Input, Output> {\n if (unchangedState(current, slot, inFlight, outcome)) return current;\n\n const { lastError, result } = current.slot === slot ? current : { lastError: null, result: undefined };\n\n if (outcome?.status === 'ok') return { inFlight, lastError: null, result: outcome.value, slot };\n\n if (outcome?.status === 'failed') return { inFlight, lastError: outcome.error, result, slot };\n\n return { inFlight, lastError, result, slot };\n}\n\nfunction useCommandSlot<Input, Output>(invoker: CommandInvoker): CommandHookController<Input, Output> {\n // Slots are inert until commit. An interrupted render cannot fence the committed source or admit its own work.\n const [slots] = useState(() => new WeakMap<object, CommandHookController<Input, Output>>());\n let slot = slots.get(invoker);\n\n if (slot === undefined) {\n slot = new CommandHookController(invoker);\n slots.set(invoker, slot);\n }\n\n return slot;\n}\n\nfunction useCommand<Input, Output>(command: Call<Input, Output>): CommandHook<Input, Output> {\n const frame = useFrame();\n const record = frame.commandRecords.get(command);\n\n if (record === undefined) {\n throw new ContributionError('missing', `Command ${command.id} is not bound in this contribution.`);\n }\n\n const currentSlot = useCommandSlot<Input, Output>(record.invoker);\n const [hookState, setHookState] = useState<CommandHookState<Input, Output>>(() => ({\n inFlight: false,\n lastError: null,\n result: undefined,\n slot: currentSlot,\n }));\n useInsertionEffect(\n () =>\n currentSlot.attach((inFlight, outcome) =>\n setHookState(current => nextState(current, currentSlot, inFlight, outcome)),\n ),\n [currentSlot],\n );\n useLayoutEffect(() => currentSlot.synchronize(), [currentSlot]);\n const { inFlight, lastError, result } = hookState.slot === currentSlot ? hookState : emptyStatus;\n const run = currentSlot.run;\n const handler = currentSlot.handler;\n\n return useMemo(() => ({ handler, inFlight, lastError, result, run }), [handler, inFlight, lastError, result, run]);\n}\n\nexport { useCommand };\nexport type { CommandHook };\n","const idleRelease = (): void => undefined;\nconst subscribeIdle = (): (() => void) => idleRelease;\nconst idleRevision = (): number => 0;\n\nexport { idleRevision, subscribeIdle };\n","import { useInsertionEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';\n\nimport type { Call } from '@opetope/core';\n\nimport type { CommandOutcome } from './command';\nimport type { CommandHook } from './command-hook';\nimport { CommandHookController } from './command-hook-controller';\nimport type { CommandInvoker } from './command-hook-controller';\nimport { ContributionError } from './errors';\nimport { idleRevision, subscribeIdle } from './idle-subscription';\nimport { useFrame } from './mount-context';\nimport type { Frame } from './mount-frame';\n\ntype CommandSelection = Readonly<Record<string, Call<never, unknown>>>;\ntype HookOf<Command> = Command extends Call<infer Input, infer Output> ? CommandHook<Input, Output> : never;\ntype CommandsHook<Commands> = {\n readonly [Key in keyof Commands]: HookOf<Commands[Key]>;\n};\nconst emptyHooks = Object.freeze({});\n\ntype CommandEntry = {\n detach: (() => void) | undefined;\n hook: CommandHook<never, unknown> & { readonly handler: () => void };\n readonly invoker: CommandInvoker;\n readonly slot: CommandHookController<never, unknown>;\n};\n\nfunction createEntry(invoker: CommandInvoker): CommandEntry {\n const slot = new CommandHookController<never, unknown>(invoker);\n\n return {\n detach: undefined,\n hook: { handler: slot.handler, inFlight: false, lastError: null, result: undefined, run: slot.run },\n invoker,\n slot,\n };\n}\n\nfunction unchangedHook(previous: CommandHook<never, unknown>, next: CommandHook<never, unknown>): boolean {\n return (\n previous.inFlight === next.inFlight &&\n Object.is(previous.result, next.result) &&\n Object.is(previous.lastError, next.lastError)\n );\n}\n\nfunction outcomeStatus(previous: CommandHook<never, unknown>, outcome: CommandOutcome<unknown> | undefined) {\n if (outcome?.status === 'ok') return { lastError: null, result: outcome.value };\n\n if (outcome?.status === 'failed') return { lastError: outcome.error, result: previous.result };\n\n return previous;\n}\n\nfunction updateEntry(entry: CommandEntry, inFlight: boolean, outcome?: CommandOutcome<unknown>): boolean {\n const previous = entry.hook;\n\n if (outcome === undefined && previous.inFlight === inFlight) return false;\n\n const { lastError, result } = outcomeStatus(previous, outcome);\n const next = { handler: entry.slot.handler, inFlight, lastError, result, run: previous.run };\n\n if (unchangedHook(previous, next)) return false;\n\n entry.hook = next;\n\n return true;\n}\n\nfunction selectEntry(previous: CommandEntry | undefined, invoker: CommandInvoker): CommandEntry {\n return previous?.invoker === invoker ? previous : createEntry(invoker);\n}\n\n/** Selection is inert during render; only a committed selection can admit work or discard an old queue. */\nclass CommandGroup {\n private entries = new Map<PropertyKey, CommandEntry>();\n private readonly listeners = new Set<() => void>();\n private revision = 0;\n\n close(): void {\n for (const entry of this.entries.values()) {\n entry.detach?.();\n entry.detach = undefined;\n }\n\n this.entries.clear();\n }\n\n commit(selected: Map<PropertyKey, CommandEntry>): void {\n for (const [key, entry] of this.entries) {\n if (selected.get(key) === entry) continue;\n\n entry.detach?.();\n entry.detach = undefined;\n }\n\n this.entries = selected;\n\n for (const entry of selected.values()) {\n entry.detach ??= entry.slot.attach((inFlight, outcome) => {\n if (!updateEntry(entry, inFlight, outcome)) return;\n\n this.revision += 1;\n\n for (const listener of this.listeners) listener();\n });\n }\n }\n\n getSnapshot = (): number => this.revision;\n\n prepare(commands: CommandSelection, frame: Frame): Map<PropertyKey, CommandEntry> {\n const selected = new Map<PropertyKey, CommandEntry>();\n\n for (const key of Reflect.ownKeys(commands)) {\n if (!Object.prototype.propertyIsEnumerable.call(commands, key)) continue;\n\n const command = (commands as Readonly<Record<PropertyKey, Call<never, unknown>>>)[key];\n const record = command === undefined ? undefined : frame.commandRecords.get(command);\n\n if (record === undefined) {\n throw new ContributionError('missing', `Command at ${String(key)} is not bound in this contribution.`);\n }\n\n selected.set(key, selectEntry(this.entries.get(key), record.invoker));\n }\n\n return selected;\n }\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n };\n}\n\nfunction useCommandGroup(commands: CommandSelection): CommandGroup | undefined {\n const groupRef = useRef<CommandGroup | undefined>(undefined);\n const populated = Reflect.ownKeys(commands).some(key => Object.prototype.propertyIsEnumerable.call(commands, key));\n\n return populated ? (groupRef.current ??= new CommandGroup()) : undefined;\n}\n\nfunction useCommands<Commands extends { readonly [Key in keyof Commands]: Call<never, unknown> }>(\n commands: Commands,\n): CommandsHook<Commands> {\n const frame = useFrame();\n const group = useCommandGroup(commands);\n const getSnapshot = group?.getSnapshot ?? idleRevision;\n useSyncExternalStore(group?.subscribe ?? subscribeIdle, getSnapshot, getSnapshot);\n const selected = group?.prepare(commands, frame);\n useInsertionEffect(() => () => group?.close(), [group]);\n useInsertionEffect(() => {\n if (selected !== undefined) group?.commit(selected);\n });\n useLayoutEffect(() => {\n if (selected === undefined) return;\n\n for (const entry of selected.values()) entry.slot.synchronize();\n });\n\n return (\n selected === undefined ? emptyHooks : Object.fromEntries([...selected].map(([key, entry]) => [key, entry.hook]))\n ) as CommandsHook<Commands>;\n}\n\nexport { useCommands };\n","import type { Readable } from '@opetope/core';\nimport { isCallTarget, isReadable } from '@opetope/core/internal';\n\nimport { ContributionError } from './errors';\nimport type { AnyCommand } from './model-binding';\n\ninterface SelectionRead {\n <Value>(source: Readable<Value>): Value;\n <Value, Selected>(source: Readable<Value>, select: (value: Value) => Selected): Selected;\n}\n\ntype SelectionContext = Readonly<{ read: SelectionRead }>;\ntype NonSelectionRecord =\n | readonly unknown[]\n | ((...arguments_: never[]) => unknown)\n | (abstract new (...arguments_: never[]) => unknown)\n | Date\n | PromiseLike<unknown>\n | ReadonlyMap<unknown, unknown>\n | ReadonlySet<unknown>\n | RegExp\n | WeakMap<object, unknown>\n | WeakSet<object>;\n/** A named interface needs no open index signature; container and callable results are not field selections. */\ntype SelectionShape<Selected extends object> = Selected extends NonSelectionRecord ? never : Selected;\ntype SelectionRecord = Readonly<Record<PropertyKey, unknown>>;\ntype SelectionSnapshot = Readonly<{\n commands: Readonly<Record<PropertyKey, AnyCommand>>;\n sources: ReadonlySet<Readable<unknown>>;\n values: SelectionRecord;\n}>;\n\nfunction readSource<Value>(source: Readable<Value>, sources: Map<Readable<unknown>, unknown>): Value {\n if (!isReadable(source)) {\n throw new ContributionError('binding-invalid', 'Model selection read requires a Readable.');\n }\n\n if (sources.has(source)) return sources.get(source) as Value;\n\n const value = source.getSnapshot();\n sources.set(source, value);\n\n return value;\n}\n\nfunction collectSelection(\n select: (context: SelectionContext) => object,\n sources: Map<Readable<unknown>, unknown>,\n): SelectionRecord {\n const read = <Value, Selected>(source: Readable<Value>, project?: (value: Value) => Selected) => {\n const value = readSource(source, sources);\n\n return project === undefined ? value : project(value);\n };\n const selected = select({ read });\n\n if (typeof selected !== 'object' || selected === null || Array.isArray(selected)) {\n throw new ContributionError('binding-invalid', 'Model selection requires a record.');\n }\n\n return Object.fromEntries(\n Reflect.ownKeys(selected)\n .filter(key => Object.prototype.propertyIsEnumerable.call(selected, key))\n .map(key => [key, (selected as SelectionRecord)[key]]),\n );\n}\n\nfunction equalSelection(previous: SelectionSnapshot, values: SelectionRecord, sources: ReadonlySet<Readable<unknown>>) {\n const keys = Reflect.ownKeys(values);\n const previousKeys = Reflect.ownKeys(previous.values);\n\n if (keys.length !== previousKeys.length || sources.size !== previous.sources.size) return false;\n\n for (const source of sources) if (!previous.sources.has(source)) return false;\n\n return keys.every((key, index) => previousKeys[index] === key && Object.is(previous.values[key], values[key]));\n}\n\ntype ModelSelector<Model> = (model: Model, context: SelectionContext) => object;\ntype SelectionReaderRef<Model> = { readonly current: ModelSelector<Model> | undefined };\n\nconst emptySelectionSnapshot: SelectionSnapshot = { commands: {}, sources: new Set(), values: {} };\n\nfunction selectionCommands(values: SelectionRecord): Readonly<Record<PropertyKey, AnyCommand>> {\n return Object.fromEntries(\n Reflect.ownKeys(values)\n .filter(key => isCallTarget(values[key]))\n .map(key => [key, values[key]]),\n ) as Readonly<Record<PropertyKey, AnyCommand>>;\n}\n\n/**\n * D214: one reader per model, not per render. The author's selector arrives through a ref, so an inline arrow does not\n * rebuild the reader; the fast path — nothing observed has moved — belongs to the selector that computed the snapshot,\n * so a new selector is always called again, its result compared field by field, and an equal selection keeps the\n * previous snapshot. A rejected or abandoned render still changes nothing: only a committed selection subscribes.\n */\nfunction createSelectionSnapshot<Model>(model: Model, selectRef: SelectionReaderRef<Model>): () => SelectionSnapshot {\n let observed: Map<Readable<unknown>, unknown> | undefined;\n let observedSelect: ModelSelector<Model> | undefined;\n let snapshot: SelectionSnapshot = emptySelectionSnapshot;\n\n return () => {\n const select = selectRef.current;\n\n if (select === undefined) return emptySelectionSnapshot;\n\n if (\n observed !== undefined &&\n observedSelect === select &&\n [...observed].every(([source, value]) => Object.is(source.getSnapshot(), value))\n ) {\n return snapshot;\n }\n\n const nextObserved = new Map<Readable<unknown>, unknown>();\n const values = collectSelection(context => select(model, context), nextObserved);\n const sources = new Set(nextObserved.keys());\n\n if (observed === undefined || !equalSelection(snapshot, values, sources)) {\n snapshot = { commands: selectionCommands(values), sources, values };\n }\n\n observed = nextObserved;\n observedSelect = select;\n\n return snapshot;\n };\n}\n\nexport { createSelectionSnapshot, emptySelectionSnapshot };\nexport type { ModelSelector, SelectionContext, SelectionShape };\n","import type { Readable } from '@opetope/core';\nimport { createAggregateError } from '@opetope/core/internal';\n\ntype Subscription = { dispose: (() => void) | undefined };\ntype Listener = Readonly<{ notify: () => void }>;\n\nfunction releaseSubscriptions(subscriptions: Iterable<Subscription>, failures: unknown[] = []): void {\n for (const subscription of subscriptions) {\n const dispose = subscription.dispose;\n subscription.dispose = undefined;\n\n try {\n dispose?.();\n } catch (error) {\n failures.push(error);\n }\n }\n\n if (failures.length === 1) throw failures[0];\n\n if (failures.length > 1) throw createAggregateError(failures, 'Model selection sources failed to release.');\n}\n\n/** A subscription set, not a scheduler: source notifications use React's snapshot consistency check. */\nclass ModelSelectionStore {\n private enabled = false;\n private readonly listeners = new Set<Listener>();\n private sources: ReadonlySet<Readable<unknown>> = new Set();\n private readonly subscriptions = new Map<Readable<unknown>, Subscription>();\n\n close(): void {\n this.enabled = false;\n this.sources = new Set();\n this.releaseAll();\n }\n\n commit(sources: ReadonlySet<Readable<unknown>>): void {\n this.sources = sources;\n this.enabled = true;\n\n try {\n this.synchronize();\n } catch (error) {\n this.releaseAll([error]);\n }\n }\n\n subscribe = (notify: () => void): (() => void) => {\n const listener = { notify };\n this.listeners.add(listener);\n\n try {\n this.synchronize();\n } catch (error) {\n this.listeners.delete(listener);\n this.releaseAll([error]);\n }\n\n return () => {\n this.listeners.delete(listener);\n\n if (this.listeners.size === 0) this.releaseAll();\n };\n };\n\n private add(source: Readable<unknown>): void {\n const subscription: Subscription = { dispose: undefined };\n // Reserve before foreign code: a synchronous notification may replace or close this selection.\n this.subscriptions.set(source, subscription);\n const dispose = source.subscribe(this.notify);\n\n if (typeof dispose !== 'function') throw new TypeError('Model selection source must return a disposer.');\n\n if (this.subscriptions.get(source) === subscription) subscription.dispose = dispose;\n else dispose();\n }\n\n private notify = (): void => {\n for (const listener of [...this.listeners]) {\n if (this.listeners.has(listener)) listener.notify();\n }\n };\n\n private releaseAll(failures?: unknown[]): void {\n const subscriptions = [...this.subscriptions.values()];\n this.subscriptions.clear();\n releaseSubscriptions(subscriptions, failures);\n }\n\n private removeUnselected(): void {\n const removed: Subscription[] = [];\n\n for (const [source, subscription] of this.subscriptions) {\n if (this.sources.has(source)) continue;\n\n this.subscriptions.delete(source);\n removed.push(subscription);\n }\n\n releaseSubscriptions(removed);\n }\n\n private synchronize(): void {\n this.removeUnselected();\n\n for (const source of this.sources) {\n if (!this.enabled || this.listeners.size === 0) return;\n\n if (this.sources.has(source) && !this.subscriptions.has(source)) this.add(source);\n }\n }\n}\n\nexport { ModelSelectionStore };\n","import { useLayoutEffect, useMemo, useRef, useSyncExternalStore } from 'react';\n\nimport type { Call, ModelOf } from '@opetope/core';\n\nimport type { CommandHook } from './command-hook';\nimport { useCommands } from './commands-hook';\nimport { ContributionError } from './errors';\nimport { subscribeIdle } from './idle-subscription';\nimport type { AnyModel } from './model-binding';\nimport { createSelectionSnapshot, emptySelectionSnapshot } from './model-selection-snapshot';\nimport type { ModelSelector, SelectionContext, SelectionShape } from './model-selection-snapshot';\nimport { ModelSelectionStore } from './model-selection-store';\nimport { useFrame } from './mount-context';\n\ntype SelectedValue<Value> = Value extends Call<infer Input, infer Output> ? CommandHook<Input, Output> : Value;\ntype ModelSelection<Selected> = { readonly [Key in keyof Selected]: SelectedValue<Selected[Key]> };\n\nconst readEmptySnapshot = () => emptySelectionSnapshot;\n\nfunction useSelectionStore(selected: boolean): ModelSelectionStore | undefined {\n const storeRef = useRef<ModelSelectionStore | undefined>(undefined);\n\n return selected ? (storeRef.current ??= new ModelSelectionStore()) : undefined;\n}\n\n/** D205: resolve only a granted model, explicitly read data, and reuse the ordinary per-key command consumers. */\nfunction useModel<Declaration extends AnyModel>(declaration: Declaration): ModelOf<Declaration>;\nfunction useModel<Declaration extends AnyModel, const Selected extends object>(\n declaration: Declaration,\n select: (model: ModelOf<Declaration>, context: SelectionContext) => Selected & SelectionShape<Selected>,\n): ModelSelection<Selected>;\nfunction useModel<Declaration extends AnyModel>(\n declaration: Declaration,\n select?: (model: ModelOf<Declaration>, context: SelectionContext) => object,\n): unknown {\n const frame = useFrame();\n\n if (!frame.models.has(declaration)) {\n throw new ContributionError('missing', `Model ${declaration.id} is not granted to this contribution.`);\n }\n\n const model = frame.models.get(declaration) as ModelOf<Declaration>;\n const store = useSelectionStore(select !== undefined);\n // D214: the selector of this render, read by a reader that belongs to the model. Writing the latest callback into\n // a ref is what `useSyncExternalStoreWithSelector` does: the reader only reads it, and never writes to it.\n const selectRef = useRef<ModelSelector<ModelOf<Declaration>> | undefined>(undefined);\n selectRef.current = select;\n const selected = select !== undefined;\n const getSnapshot = useMemo(\n () => (selected ? createSelectionSnapshot(model, selectRef) : readEmptySnapshot),\n [model, selected],\n );\n const snapshot = useSyncExternalStore(store?.subscribe ?? subscribeIdle, getSnapshot, getSnapshot);\n const commands = useCommands(snapshot.commands);\n useLayoutEffect(() => () => store?.close(), [store]);\n useLayoutEffect(() => store?.commit(snapshot.sources), [snapshot, store]);\n\n if (select === undefined) return model;\n\n return Object.fromEntries(\n Reflect.ownKeys(snapshot.values).map(key => [\n key,\n Object.prototype.hasOwnProperty.call(commands, key) ? commands[key] : snapshot.values[key],\n ]),\n );\n}\n\nexport { useModel };\n","import type { FunctionComponent } from 'react';\n\nimport type { ModelIdentity } from '@opetope/core/internal';\n\nimport { ContributionError } from './errors';\n\ntype AnyModel = ModelIdentity;\n\n/**\n * The marker a component uses to state which UI models of its contribution it reads. `slot` checks by type that the\n * contribution grants every model of this list — it may grant more, because the mount serves its whole instance.\n *\n * The runtime authority is the mount frame, not this marker: `useModel` resolves against what the mount was given\n * and refuses anything else. The lint rule `opetope/require-declared-models` checks visible contribution sites and\n * each reader of a per-mount model within the same module. Imported implementations and dynamic declaration lists\n * remain unknown to this syntactic check (D85, D158, D250).\n */\ntype ComponentRequiringModels<Props, Models extends readonly AnyModel[]> = FunctionComponent<Props> & {\n readonly requires: Models;\n};\n\nfunction requiresModels<const Models extends readonly AnyModel[]>(\n models: Models,\n): <Props>(component: FunctionComponent<Props>) => ComponentRequiringModels<Props, Models> {\n const declared = Object.freeze([...models]) as unknown as Models;\n\n return <Props>(component: FunctionComponent<Props>): ComponentRequiringModels<Props, Models> => {\n const existing = (component as { readonly requires?: readonly AnyModel[] }).requires;\n\n if (existing !== undefined) {\n throw new ContributionError('duplicate', 'Component already declares the models it requires.');\n }\n\n Object.defineProperty(component, 'requires', { enumerable: false, value: declared });\n\n return component as ComponentRequiringModels<Props, Models>;\n };\n}\n\nexport { requiresModels };\n","import { useCallback, useEffect, useSyncExternalStore } from 'react';\n\nimport type { Resource, ResourceSnapshot } from '@opetope/runtime';\nimport type { ResourceRequestKey } from '@opetope/runtime/internal';\n\nfunction useResource<Data, Key extends ResourceRequestKey>(resource: Resource<Data, Key>): ResourceSnapshot<Data, Key> {\n const subscribe = useCallback((listener: () => void) => resource.subscribe(listener), [resource]);\n // D199: a resource is a structural contract, so it may be an object with methods. Reading through it keeps the\n // receiver the adapter expects; handing `resource.getSnapshot` to React would call it with none.\n const getSnapshot = useCallback(() => resource.getSnapshot(), [resource]);\n const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n useEffect(() => resource.retain(), [resource]);\n\n return snapshot;\n}\n\nexport { useResource };\n","import type { ComponentType, ReactNode } from 'react';\nimport { createElement, Fragment } from 'react';\n\nimport type { DeclarationId } from '@opetope/core';\nimport { declarationId } from '@opetope/core';\nimport type { ContributionTarget } from '@opetope/core/internal';\nimport { createContributionTarget } from '@opetope/core/internal';\nimport type { ContributionModel } from '@opetope/runtime/internal';\n\nimport { contributionAuthority, ContributionMount } from './contribution-frame';\nimport { useReadable } from './readable-hooks';\n\ntype SlotProperties = object | undefined;\ntype EmptySlotProperties = Readonly<Record<string, never>>;\ntype SlotComponentProperties<Props extends SlotProperties> = [Props] extends [undefined]\n ? EmptySlotProperties\n : Extract<Props, object>;\n\n/**\n * What a contribution publishes: the component, the optional props adapter and the optional UI models the mount\n * creates. Without an adapter the component takes the slot props; with one it takes exactly the adapter result (D85).\n */\ntype SlotContribution<Props extends SlotProperties = undefined> = {\n readonly Component: ComponentType<never>;\n readonly models?: readonly ContributionModel[];\n readonly props?: (slotProps: SlotComponentProperties<Props>) => object;\n};\n\ntype SlotTarget<Props extends SlotProperties = undefined> = ContributionTarget<SlotContribution<Props>>;\n\ntype SwitchSlotTarget<Route extends string, Props extends SlotProperties = undefined> = ((\n route: Route,\n) => SlotTarget<Props>) & {\n readonly id: DeclarationId;\n};\n\ntype SlotRenderProps<Props extends SlotProperties> = [Props] extends [undefined]\n ? {\n readonly props?: never;\n readonly target: SlotTarget<Props>;\n }\n : {\n readonly props: SlotComponentProperties<Props>;\n readonly target: SlotTarget<Props>;\n };\n\nconst emptySlotProperties: EmptySlotProperties = Object.freeze({});\n\nfunction defineSlot<Props extends SlotProperties = undefined>(options: { readonly id: string }): SlotTarget<Props> {\n return createContributionTarget<SlotContribution<Props>>(options, 'slot');\n}\n\nfunction defineSwitchSlot<Route extends string, Props extends SlotProperties = undefined>(options: {\n readonly id: string;\n}): SwitchSlotTarget<Route, Props> {\n const id = declarationId(options.id);\n const targets = new Map<Route, SlotTarget<Props>>();\n\n const switchSlot = (route: Route): SlotTarget<Props> => {\n const existing = targets.get(route);\n\n if (existing !== undefined) return existing;\n\n const target = defineSlot<Props>({ id: `${id}/${route}` });\n targets.set(route, target);\n\n return target;\n };\n\n Object.defineProperty(switchSlot, 'id', { enumerable: true, value: id });\n\n return Object.freeze(switchSlot) as SwitchSlotTarget<Route, Props>;\n}\n\n/**\n * Every contribution renders inside its own mount: the models its generation owns plus the UI models it declared,\n * created on mount and closed on unmount (D70, D85).\n */\nfunction Slot<Props extends SlotProperties>(options: SlotRenderProps<Props>): ReactNode {\n const entries = useReadable(options.target.entries);\n const slotProps: object = 'props' in options ? (options.props ?? emptySlotProperties) : emptySlotProperties;\n\n if (entries.length === 0) return null;\n\n return entries.map(entry =>\n createElement(\n Fragment,\n { key: entry.id },\n createElement(ContributionMount, {\n authority: contributionAuthority(entry),\n contribution: entry.value,\n contributionId: entry.id,\n slotProps,\n targetId: options.target.id,\n }),\n ),\n );\n}\n\nexport { defineSlot, defineSwitchSlot, Slot };\nexport type { SlotComponentProperties, SlotContribution, SlotProperties, SlotTarget, SwitchSlotTarget };\n"],"names":["failureOutcome","options","error","isCancellation","notification","_a","reportDetachedError","callbackError","runOptions","onSuccess","signal","requestOf","input","resolve","promise","settle","request","outcome","CommandHookController","ContributionError","aborted","invoker","notify","CallError","compatibleAbortReason","invocation","value","emptyStatus","unchangedState","current","slot","inFlight","nextState","lastError","result","useCommandSlot","slots","useState","useCommand","command","record","useFrame","currentSlot","hookState","setHookState","useInsertionEffect","useLayoutEffect","run","handler","useMemo","idleRelease","subscribeIdle","idleRevision","emptyHooks","createEntry","unchangedHook","previous","next","outcomeStatus","updateEntry","entry","selectEntry","CommandGroup","selected","key","listener","commands","frame","useCommandGroup","groupRef","useRef","useCommands","group","getSnapshot","useSyncExternalStore","readSource","source","sources","isReadable","collectSelection","select","project","equalSelection","values","keys","previousKeys","index","emptySelectionSnapshot","selectionCommands","isCallTarget","createSelectionSnapshot","model","selectRef","observed","observedSelect","snapshot","nextObserved","context","releaseSubscriptions","subscriptions","failures","subscription","dispose","createAggregateError","ModelSelectionStore","removed","readEmptySnapshot","useSelectionStore","storeRef","useModel","declaration","store","requiresModels","models","declared","component","useResource","resource","subscribe","useCallback","useEffect","emptySlotProperties","defineSlot","createContributionTarget","defineSwitchSlot","id","declarationId","targets","switchSlot","route","existing","target","Slot","entries","useReadable","slotProps","createElement","Fragment","ContributionMount","contributionAuthority"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opetope/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=20.19.0"
|
|
6
6
|
},
|
|
@@ -50,16 +50,16 @@
|
|
|
50
50
|
}
|
|
51
51
|
],
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@opetope/core": "0.
|
|
54
|
-
"@opetope/runtime": "0.
|
|
53
|
+
"@opetope/core": "0.7.0",
|
|
54
|
+
"@opetope/runtime": "0.7.0",
|
|
55
55
|
"@testing-library/react": "16.3.3",
|
|
56
56
|
"@types/react": "19.2.18",
|
|
57
57
|
"react": "19.2.8",
|
|
58
58
|
"react-dom": "19.2.8"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@opetope/core": "0.
|
|
62
|
-
"@opetope/runtime": "0.
|
|
61
|
+
"@opetope/core": "0.7.0",
|
|
62
|
+
"@opetope/runtime": "0.7.0",
|
|
63
63
|
"react": ">=19.0.0 <20"
|
|
64
64
|
},
|
|
65
65
|
"sideEffects": false,
|