@opetope/react 0.14.0 → 0.16.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 +118 -0
- package/README.md +67 -48
- package/dist/act-delivery.d.ts +20 -0
- package/dist/command-hook-controller.d.ts +13 -3
- package/dist/command-hook.d.ts +8 -8
- package/dist/contribution-frame-DL0dyVP4.js +2 -0
- package/dist/contribution-frame-DL0dyVP4.js.map +1 -0
- package/dist/{contribution-isolation-Bzfbt4iM.js → contribution-isolation-Ig70xFiC.js} +2 -2
- package/dist/contribution-isolation-Ig70xFiC.js.map +1 -0
- package/dist/contribution-isolation.d.ts +3 -3
- package/dist/errors.d.ts +4 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integration.d.ts +0 -4
- package/dist/integration.js +1 -1
- package/dist/integration.js.map +1 -1
- package/dist/model-hook.d.ts +5 -4
- package/dist/model-selection-snapshot.d.ts +6 -7
- package/dist/readable-hooks.d.ts +5 -8
- package/dist/requires-models.d.ts +4 -7
- package/dist/resource-command.d.ts +25 -26
- package/dist/resource-hook.d.ts +3 -7
- package/dist/resource-verb-hook.d.ts +28 -0
- package/dist/scenario-diagnostics.d.ts +3 -1
- package/dist/scenario-mount.d.ts +2 -1
- package/dist/scenario-slot.d.ts +6 -15
- package/dist/scenario-types.d.ts +68 -11
- package/dist/scenario-wait.d.ts +8 -1
- package/dist/scenario.d.ts +5 -3
- package/dist/selection-hooks.d.ts +6 -4
- package/dist/selector-sources.d.ts +64 -0
- package/dist/slot.d.ts +9 -7
- package/dist/testing.d.ts +2 -8
- package/dist/testing.js +3 -3
- package/dist/testing.js.map +1 -1
- package/package.json +5 -5
- package/dist/contribution-frame-Bh104T5Z.js +0 -2
- package/dist/contribution-frame-Bh104T5Z.js.map +0 -1
- package/dist/contribution-isolation-Bzfbt4iM.js.map +0 -1
- package/dist/feature-boundary.d.ts +0 -29
- package/dist/feature-demand.d.ts +0 -21
package/dist/slot.d.ts
CHANGED
|
@@ -6,8 +6,7 @@ type SlotProperties = object | undefined;
|
|
|
6
6
|
type EmptySlotProperties = Readonly<Record<string, never>>;
|
|
7
7
|
type SlotComponentProperties<Props extends SlotProperties> = [Props] extends [undefined] ? EmptySlotProperties : Extract<Props, object>;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* creates. Without an adapter the component takes the slot props; with one it takes exactly the adapter result (D85).
|
|
9
|
+
* Contribution component and adapter published for a Slot target.
|
|
11
10
|
*/
|
|
12
11
|
type SlotContribution<Props extends SlotProperties = undefined> = {
|
|
13
12
|
readonly Component: ComponentType<never>;
|
|
@@ -19,19 +18,22 @@ type SwitchSlotTarget<Route extends string, Props extends SlotProperties = undef
|
|
|
19
18
|
readonly id: DeclarationId;
|
|
20
19
|
};
|
|
21
20
|
type SlotRenderProps<Props extends SlotProperties> = [Props] extends [undefined] ? {
|
|
22
|
-
readonly props?:
|
|
21
|
+
readonly props?: 'this slot has no props: omit the props field';
|
|
23
22
|
readonly target: SlotTarget<Props>;
|
|
24
23
|
} : {
|
|
25
24
|
readonly props: SlotComponentProperties<Props>;
|
|
26
25
|
readonly target: SlotTarget<Props>;
|
|
27
26
|
};
|
|
28
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Declare a typed Slot target by its id.
|
|
29
|
+
*/
|
|
29
30
|
declare function defineSlot<Props extends SlotProperties = undefined>(id: string): SlotTarget<Props>;
|
|
30
31
|
declare function defineSwitchSlot<Route extends string, Props extends SlotProperties = undefined>(id: string): SwitchSlotTarget<Route, Props>;
|
|
31
32
|
/**
|
|
32
|
-
*
|
|
33
|
-
* created on mount and closed on unmount (D70, D85).
|
|
33
|
+
* Render the published contributions of a Slot target within their owning mounts.
|
|
34
34
|
*/
|
|
35
|
-
declare function Slot<Props extends SlotProperties>(options: SlotRenderProps<Props
|
|
35
|
+
declare function Slot<Props extends SlotProperties>(options: SlotRenderProps<NoInfer<Props>> & {
|
|
36
|
+
readonly target: SlotTarget<Props>;
|
|
37
|
+
}): ReactNode;
|
|
36
38
|
export { defineSlot, defineSwitchSlot, Slot };
|
|
37
39
|
export type { SlotComponentProperties, SlotContribution, SlotProperties, SlotTarget, SwitchSlotTarget };
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Every word of the entry below, except one: `command` is shadowed here by the fixture that also registers the
|
|
3
|
-
* contribution binding a mount reads, so the React name keeps meaning the stronger thing it has always meant. The
|
|
4
|
-
* core fixture is the same Command without that binding, and a test that wants it names `@opetope/core/testing` (D300).
|
|
5
|
-
*/
|
|
6
|
-
export { CommandTimeoutError, eventually, openModel, runCommand, settled, testReadable, testResourceEpoch, waitFor, WaitTimeoutError, yieldTurn, } from '@opetope/runtime/testing';
|
|
7
|
-
export type { CommandInputArgs, EventuallyOptions, ModelInstance, OpenModelOptions, RunCommandOptions, SettleTarget, WaitOptions, } from '@opetope/runtime/testing';
|
|
1
|
+
/** React test entry for scenario ownership and slot rendering. */
|
|
8
2
|
export { createScenario } from './scenario.js';
|
|
9
3
|
export { ScenarioTimeoutError } from './scenario-diagnostics.js';
|
|
10
|
-
export {
|
|
4
|
+
export { renderSlot } from './scenario-slot.js';
|
|
11
5
|
export type { SlotTestFixture, SlotTestHarness } from './scenario-slot.js';
|
|
12
6
|
export type { Scenario, ScenarioHost, ScenarioHostMount, ScenarioMount, ScenarioOptions, ScenarioOwnership, ScenarioWaitOptions, } from './scenario-types.js';
|
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`)}class
|
|
3
|
-
${
|
|
1
|
+
import{hasOwn as O,isResourceView as x,createAggregateError as Q}from"@opetope/core/internal";import{openApplication as X}from"@opetope/runtime";import{createInspectionSession as Y,testingTimeoutMs as Z}from"@opetope/runtime/internal";import{a as N,u as _,c as q,M as ee,i as te}from"./contribution-frame-DL0dyVP4.js";import{createElement as ne}from"react";import{declarationId as re}from"@opetope/core";function oe(e){if(e.state.kind==="ready")return[];const t=e.state.kind==="waiting"?` (${e.state.reason})`:"";return[`Feature ${e.label}: ${e.state.kind}${t}.`]}function se(e){if(e.lane===null)return`Command ${e.declaration}: ${e.state}; lane parallel; blockers none (parallel).`;const t=e.lane.blockedBy==="unknown"?"unknown":e.lane.blockedBy.join(", ");return`Command ${e.declaration}: ${e.state}; lane ${e.lane.declaration}; blockers ${t}.`}function ie(e){if(e===void 0)return["Runtime activity: unknown."];const t=[];return(e.freshness==="stale"||e.truncated)&&t.push(`Activity: ${e.freshness}${e.truncated?", truncated":""}; completeness unknown.`),[...t,...e.features.map(n=>`Feature ${n.feature}: ${n.phase}; body ${n.body}; host demand unknown.`),...e.calls.map(se),...e.resources.map(n=>`Resource ${n.id}: ${n.state}; leases ${String(n.leases)}.`)]}function ce(e){const t=[...e.runtime.conditions.flatMap(n=>n.state.kind==="true"?[]:[`Condition ${n.label}: ${n.state.kind}.`]),...e.runtime.instances.flatMap(oe),...ie(e.activity)];return t.length===0?"No registered runtime blocker observed; external UI and host work are unknown.":t.join(`
|
|
2
|
+
`)}class W extends Error{label;timeoutMs;snapshot;history;code="timeout";constructor(t,n,r,s){super(`Scenario timed out after ${String(n)}ms: ${t}.
|
|
3
|
+
${ce(r)}`),this.label=t,this.timeoutMs=n,this.snapshot=r,this.history=s,this.name="ScenarioTimeoutError"}}function ae(e,t){return!t||e===void 0?!1:e.closed&&!e.truncated}function ue(e,t,n){if(e===void 0)return["Runtime activity is unavailable."];const r=[];return e.truncated&&r.push("The activity snapshot is truncated."),e.freshness==="stale"&&!t&&r.push("The activity snapshot is stale."),n||r.push("Successful application and mount cleanup has not been observed."),Object.freeze(r)}function le(e,t){return e===void 0||e.truncated||e.freshness==="stale"&&!t?{calls:"unknown",features:"unknown",resources:"unknown"}:{calls:e.calls.length,features:e.features.length,resources:e.resources.length}}function de(e,t){const n=e.activity,r=ae(n,t);return Object.freeze({...le(n,r),closed:t,reasons:ue(n,r,t),scope:"registered-runtime",status:r?"complete":"unknown"})}class fe{released;act;get closed(){return this.completion!==void 0}available=!1;completion;handle;reject;resolve;constructor(t,n){this.released=t,this.act=n}close=()=>this.completion!==void 0?this.completion:(this.completion=new Promise((t,n)=>{this.resolve=t,this.reject=n}),this.available&&this.releaseAvailable(),this.completion);provide(t){this.available=!0,this.handle=t,this.closed&&this.releaseAvailable()}finish(t,n){const r=this.resolve,s=this.reject;this.resolve=void 0,this.reject=void 0,this.released(t,n),t?s==null||s(n):r==null||r()}releaseAvailable(){const t=this.handle;this.handle=void 0,this.available=!1;try{const n=()=>t==null?void 0:t.unmount();Promise.resolve(this.act===void 0?n():N(this.act,n)).then(()=>this.finish(!1),r=>this.finish(!0,r))}catch(n){this.finish(!0,n)}}}const he=re("testing.contribution");function B(e,t={}){const n=t.models??[];let r=t.props??{};const s=new Set,g={getSnapshot:()=>r,subscribe:p=>(s.add(p),()=>s.delete(p))},w=t.contribution,m=t.reporter,u=m===void 0?void 0:{models:[],reporter:m};return Object.freeze({close:()=>{r={},s.clear()},Slot:()=>{const p=_(e.entries),l=_(g);return(w===void 0?p.map(i=>[i.id,i.value,q(i)??u]):[[he,w,u]]).map(([i,$,M])=>ne(ee,{authority:M,contribution:$,contributionId:i,fixtures:n,key:i,slotProps:l,targetId:e.id}))},updateProps:p=>{r=p;for(const l of[...s])l()}})}function pe(e,t={}){const n=B(e,t);return Object.freeze({Slot:n.Slot,updateProps:n.updateProps})}function T(e,t){if(!Number.isFinite(e)||e<=0||e>2147483647)throw new RangeError(`${t} must be a finite duration from 0 (exclusive) to 2147483647ms.`);return e}class me{source;listeners=new Set;pending=new Set;constructor(t){this.source=t}cancel(){for(const t of[...this.pending])t(new Error("Scenario is closing."))}deadline(t,n,r=this.source.timeoutMs){return T(r,"Scenario timeoutMs"),new Promise((s,g)=>{const w=setTimeout(()=>g(this.timeout(n,r)),r);Promise.resolve(t).then(m=>{clearTimeout(w),s(m)},m=>{clearTimeout(w),g(m)})})}notify=()=>{for(const t of[...this.listeners])t()};waitFor(t,n,r){const s=T(r.timeoutMs??this.source.timeoutMs,"Scenario timeoutMs"),g=T(r.pollIntervalMs??10,"Scenario pollIntervalMs"),w=t.kind==="source"?t.read:()=>t.read(this.source.getSnapshot()),m=(u,k)=>{if(u!==null&&(typeof u=="object"||typeof u=="function")&&typeof Reflect.get(u,"then")=="function")throw new TypeError(`Scenario.waitFor ${k} synchronously; put an awaited read inside eventually.`);return u};return new Promise((u,k)=>{let p=!1,l=()=>{};const y=(c,C=!1)=>{p||(p=!0,l(),C?k(c):u(c))},i=()=>{if(!p)try{const c=m(w(),"reads");(n===void 0?c!==!1&&c!==null&&c!==void 0:m(n(c),"decides"))&&y(c)}catch(c){y(c,!0)}},$=c=>y(c,!0),M=setTimeout(()=>y(this.timeout(r.label??(t.kind==="source"?"waitFor(source)":"waitFor"),s),!0),s),S=setInterval(i,g);l=()=>{clearTimeout(M),clearInterval(S),this.listeners.delete(i),this.pending.delete($)},this.listeners.add(i),this.pending.add($),i()})}timeout(t,n){return new W(t,n,this.source.getSnapshot(),this.source.history())}}function H(e,t){if(!Number.isSafeInteger(e)||e<1||e>1e4)throw new RangeError(`${t} must be an integer from 1 to 10000.`);return e}function we(e){if(e===null||typeof e!="object"||!("mount"in e)||typeof e.mount!="function")throw new TypeError("Scenario requires a host.mount(Component) adapter.")}function ye(e){return x(e)?!0:(typeof e!="object"||e===null)&&typeof e!="function"?!1:"getSnapshot"in e&&typeof e.getSnapshot=="function"}function be(e,t){return{...e.cleanupFailure===void 0?{}:{cleanupFailure:e.cleanupFailure},...O(e,"conditions")?{conditions:e.conditions}:{},...O(e,"grace")?{grace:e.grace}:{},...O(e,"imports")?{imports:e.imports}:{},reporter:t}}const ge=()=>{};function Se(e){if(O(e,"act")&&typeof e.act!="function")throw new TypeError("Scenario act must be the renderer's act function; leave it out to render without one.");return e.act}function ke(e){if(e!=="collect")return{reporter:e};const t=[];return{reported:t,reporter:n=>{t.push(n)}}}function $e(e,t){const n=t.timeoutMs;n!==void 0&&T(n,"Scenario timeoutMs");const r=Se(t),s=o=>r===void 0?o():N(r,o),g=()=>r===void 0?ge:te(r),w=H(t.historyCapacity??64,"Scenario historyCapacity"),m=H(t.activityCapacity??256,"Scenario activityCapacity");let u=t.host;we(u);const{reported:k,reporter:p}=ke(t.reporter);let l=X(e,be(t,p)),y;try{y=Y(l,{activityCapacity:m,ringCapacity:w})}catch(o){throw l.ready.catch(()=>{}),l.close().catch(()=>{}),o}let i="open",$=!1,M=!1;const S=[],c=new Set,C=[],P=()=>y.getSnapshot(),R=()=>Object.freeze([...S]),j=new me({getSnapshot:P,history:R,get timeoutMs(){return n??Z()}}),A=()=>{if(!M){M=!0;try{const o=P(),d=S[S.length-1];((d==null?void 0:d.stateRevision)!==o.stateRevision||d.activity!==o.activity)&&(S.push(o),S.length>w&&S.shift())}finally{M=!1}j.notify()}},V=y.subscribe(A);A();const I=j.deadline(l.ready,"application ready");I.catch(()=>{});let E,v;const D=()=>{if(E!==void 0)return E;let o,d;E=new Promise((f,a)=>{o=f,d=a}),i="closing",j.cancel();const b=[];try{b.push(l.close())}catch(f){b.push(Promise.reject(f))}return b.push(...[...c].map(f=>f.close())),Promise.allSettled(b).then(f=>{const a=[...new Set([...C,...f.flatMap(h=>h.status==="rejected"?[h.reason]:[])])];C.length=0,i="closed";try{A()}catch(h){a.push(h)}finally{V(),y.close(),c.clear(),l=void 0,u=void 0}$=a.length===0,a.length===0?o():d(Q(a,"Scenario cleanup failed."))}),E},L=()=>{const o=D();return v!==void 0||(v=j.deadline(o,"scenario close"),v.catch(()=>{i==="closing"&&(v=void 0)})),v},U=()=>v??s(L),G=(o,d={})=>{if(i!=="open")throw new Error("Scenario is closing.");const b=B(o,d),f=g(),a=new fe((F,K)=>{c.delete(a),b.close(),f(),F&&C.push(K)},r);c.add(a);let h;try{if(h=s(()=>u.mount(b.Slot)),h===null||typeof h!="object"||typeof h.unmount!="function")throw new TypeError("Scenario host.mount must return an unmount() handle.");a.provide(h)}catch(F){throw f(),a.provide(void 0),a.close().catch(()=>{}),F}return Object.freeze({host:h,unmount:a.close,updateProps:F=>{if(i!=="open"||a.closed)throw new Error("Scenario mount is closed.");s(()=>b.updateProps(F)),j.notify()}})};function J(o,d,b){if(i!=="open")return Promise.reject(new Error("Scenario is closing."));const f=typeof d=="function"?d:void 0,a=(f===void 0?d:b)??{},h=x(o)?{kind:"source",read:()=>o.observe().getSnapshot()}:ye(o)?{kind:"source",read:()=>o.getSnapshot()}:{kind:"graph",read:o};return j.waitFor(h,f,a)}const z={close:U,getSnapshot:P,history:R,mount:G,notify:()=>{i==="open"&&j.notify()},ownership:()=>de(P(),$),ready:I,waitFor:J};return k!==void 0&&Object.defineProperty(z,"reported",{enumerable:!0,get:()=>Object.freeze([...k])}),Object.freeze(z)}export{W as ScenarioTimeoutError,$e as createScenario,pe as renderSlot};
|
|
4
4
|
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sources":["../src/scenario-diagnostics.ts","../src/scenario-mount.ts","../src/scenario-slot.tsx","../src/scenario-wait.ts","../src/scenario.ts"],"sourcesContent":["import type { RuntimeActivitySnapshot, RuntimeGraphSnapshot } from '@opetope/runtime/internal';\n\nimport type { ScenarioOwnership } from './scenario-types';\n\nfunction instanceFacts(instance: RuntimeGraphSnapshot['runtime']['instances'][number]): readonly string[] {\n if (instance.state.kind === 'ready') return [];\n\n const waiting = instance.state.kind === 'waiting' ? ` (${instance.state.reason})` : '';\n\n return [`Feature ${instance.label}: ${instance.state.kind}${waiting}.`];\n}\n\nfunction callFact(call: RuntimeActivitySnapshot['calls'][number]): string {\n if (call.lane === null) return `Command ${call.declaration}: ${call.state}; lane parallel; blockers none (parallel).`;\n\n const blockers = call.lane.blockedBy === 'unknown' ? 'unknown' : call.lane.blockedBy.join(', ');\n\n return `Command ${call.declaration}: ${call.state}; lane ${call.lane.declaration}; blockers ${blockers}.`;\n}\n\nfunction activityFacts(activity: RuntimeActivitySnapshot | undefined): readonly string[] {\n if (activity === undefined) return ['Runtime activity: unknown.'];\n\n const facts: string[] = [];\n\n if (activity.freshness === 'stale' || activity.truncated) {\n facts.push(`Activity: ${activity.freshness}${activity.truncated ? ', truncated' : ''}; completeness unknown.`);\n }\n\n return [\n ...facts,\n ...activity.features.map(\n feature => `Feature ${feature.feature}: ${feature.phase}; body ${feature.body}; host demand unknown.`,\n ),\n ...activity.calls.map(callFact),\n ...activity.resources.map(\n resource => `Resource ${resource.id}: ${resource.state}; leases ${String(resource.leases)}.`,\n ),\n ];\n}\n\nfunction explainSnapshot(snapshot: RuntimeGraphSnapshot): string {\n const facts = [\n ...snapshot.runtime.conditions.flatMap(condition =>\n condition.state.kind === 'true' ? [] : [`Condition ${condition.label}: ${condition.state.kind}.`],\n ),\n ...snapshot.runtime.instances.flatMap(instanceFacts),\n ...activityFacts(snapshot.activity),\n ];\n\n return facts.length === 0\n ? 'No registered runtime blocker observed; external UI and host work are unknown.'\n : facts.join('\\n');\n}\n\n/** D206: the failure carries the producer's same data-only graph/activity facts, without product payloads. */\nclass ScenarioTimeoutError extends Error {\n readonly code = 'timeout';\n\n constructor(\n readonly label: string,\n readonly timeoutMs: number,\n readonly snapshot: RuntimeGraphSnapshot,\n readonly history: readonly RuntimeGraphSnapshot[],\n ) {\n super(`Scenario timed out after ${String(timeoutMs)}ms: ${label}.\\n${explainSnapshot(snapshot)}`);\n this.name = 'ScenarioTimeoutError';\n }\n}\n\nfunction ownershipComplete(activity: RuntimeActivitySnapshot | undefined, successfullyClosed: boolean): boolean {\n if (!successfullyClosed || activity === undefined) return false;\n\n return activity.closed && !activity.truncated;\n}\n\nfunction ownershipReasons(\n activity: RuntimeActivitySnapshot | undefined,\n complete: boolean,\n successfullyClosed: boolean,\n): readonly string[] {\n if (activity === undefined) return ['Runtime activity is unavailable.'];\n\n const reasons: string[] = [];\n\n if (activity.truncated) reasons.push('The activity snapshot is truncated.');\n\n if (activity.freshness === 'stale' && !complete) reasons.push('The activity snapshot is stale.');\n\n if (!successfullyClosed) reasons.push('Successful application and mount cleanup has not been observed.');\n\n return Object.freeze(reasons);\n}\n\nfunction ownershipCounts(\n activity: RuntimeActivitySnapshot | undefined,\n complete: boolean,\n): Pick<ScenarioOwnership, 'calls' | 'features' | 'resources'> {\n if (activity === undefined || activity.truncated || (activity.freshness === 'stale' && !complete)) {\n return { calls: 'unknown', features: 'unknown', resources: 'unknown' };\n }\n\n return { calls: activity.calls.length, features: activity.features.length, resources: activity.resources.length };\n}\n\nfunction scenarioOwnership(snapshot: RuntimeGraphSnapshot, successfullyClosed: boolean): ScenarioOwnership {\n const activity = snapshot.activity;\n const complete = ownershipComplete(activity, successfullyClosed);\n\n return Object.freeze({\n ...ownershipCounts(activity, complete),\n closed: successfullyClosed,\n reasons: ownershipReasons(activity, complete, successfullyClosed),\n scope: 'registered-runtime',\n status: complete ? 'complete' : 'unknown',\n });\n}\n\nexport { scenarioOwnership, ScenarioTimeoutError };\n","import type { ScenarioHostMount } from './scenario-types';\n\n/** A reservation exists before the host callback, so reentrant close also owns a mount returned later. */\nclass ScenarioMountLease<Mounted extends ScenarioHostMount> {\n get closed(): boolean {\n return this.completion !== undefined;\n }\n private available = false;\n private completion: Promise<void> | undefined;\n private handle: Mounted | undefined;\n private reject: ((error: unknown) => void) | undefined;\n\n private resolve: (() => void) | undefined;\n\n constructor(private readonly released: (failed: boolean, error?: unknown) => void) {}\n\n readonly close = (): Promise<void> => {\n if (this.completion !== undefined) return this.completion;\n\n this.completion = new Promise<void>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n\n if (this.available) this.releaseAvailable();\n\n return this.completion;\n };\n\n provide(handle: Mounted | undefined): void {\n this.available = true;\n this.handle = handle;\n\n if (this.closed) this.releaseAvailable();\n }\n\n private finish(failed: boolean, error?: unknown): void {\n const resolve = this.resolve;\n const reject = this.reject;\n this.resolve = undefined;\n this.reject = undefined;\n this.released(failed, error);\n\n if (!failed) resolve?.();\n else reject?.(error);\n }\n\n private releaseAvailable(): void {\n const handle = this.handle;\n this.handle = undefined;\n this.available = false;\n try {\n Promise.resolve(handle?.unmount()).then(\n () => this.finish(false),\n (error: unknown) => this.finish(true, error),\n );\n } catch (error) {\n this.finish(true, error);\n }\n }\n}\n\nexport { ScenarioMountLease };\n","import { createElement } from 'react';\nimport type { FC, ReactNode } from 'react';\n\nimport { declarationId } from '@opetope/core';\nimport type { Command } from '@opetope/core';\nimport { command as callFixture } from '@opetope/core/testing';\n\nimport { bindCommand } from './command';\nimport { contributionAuthority, ContributionMount } from './contribution-frame';\nimport type { ContributionValue, ModelFixture } from './contribution-frame';\nimport { useReadable } from './readable-hooks';\nimport type { SlotComponentProperties, SlotContribution, SlotProperties, SlotTarget } from './slot';\n\n/**\n * Two forms, as `renderRoot` had (D19): without `contribution` the harness mounts what the target published, with it\n * the harness mounts one fixture contribution so a component test needs no generation.\n */\ntype SlotTestFixture<Props extends SlotProperties> = {\n readonly contribution?: SlotContribution<Props>;\n readonly models?: readonly ModelFixture[];\n readonly props?: SlotComponentProperties<Props>;\n /**\n * Where a contained mount failure is reported (D256). A component test has no feature to report to, so without it\n * the failure is detached and the assertion has nothing to read.\n */\n readonly reporter?: (error: unknown) => void;\n};\n\ninterface SlotTestHarness<Props extends SlotProperties> {\n readonly Slot: FC;\n readonly updateProps: (props: SlotComponentProperties<Props>) => void;\n}\n\nconst testingContributionId = declarationId('testing.contribution');\n\n/**\n * A command a fixture publishes: the test writes the body, the harness gives it the identity a model requires. The\n * Command itself is the core fixture (D300); what this word adds, and what keeps it in the React package, is the\n * contribution binding a mount reads (D285).\n */\nfunction command<Input = void, Output = void>(\n run: (context: { readonly input: Input; readonly signal: AbortSignal }) => Output | PromiseLike<Output>,\n): Command<Input, Output> {\n return bindCommand(callFixture<Input, Output>(run));\n}\n\n/**\n * Mounts the contributions of one slot the way a host does, with optional model fixtures for a component test. D19 and D85: the same\n * ContributionMount is shared by component tests and the application scenario harness (D206).\n */\nfunction createSlotHarness<Props extends SlotProperties>(\n target: SlotTarget<Props>,\n fixture: SlotTestFixture<Props> = {},\n): SlotTestHarness<Props> & { readonly close: () => void } {\n const fixtures = fixture.models ?? [];\n let current: object = fixture.props ?? {};\n const listeners = new Set<() => void>();\n const props = {\n getSnapshot: (): object => current,\n subscribe: (listener: () => void): (() => void) => {\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n };\n\n const supplied = fixture.contribution;\n const reported = fixture.reporter;\n const fixtureAuthority = reported === undefined ? undefined : { models: [], reporter: reported };\n const Mounted: FC = (): ReactNode => {\n const published = useReadable(target.entries);\n const slotProps = useReadable(props);\n const entries =\n supplied === undefined\n ? published.map(\n entry =>\n [entry.id, entry.value as ContributionValue, contributionAuthority(entry) ?? fixtureAuthority] as const,\n )\n : [[testingContributionId, supplied as unknown as ContributionValue, fixtureAuthority] as const];\n\n return entries.map(([contributionId, contribution, authority]) =>\n createElement(ContributionMount, {\n authority,\n contribution,\n contributionId,\n fixtures,\n key: contributionId,\n slotProps,\n targetId: target.id,\n }),\n );\n };\n\n return Object.freeze({\n close: (): void => {\n current = {};\n listeners.clear();\n },\n Slot: Mounted,\n updateProps: (next: SlotComponentProperties<Props>): void => {\n current = next;\n\n for (const listener of [...listeners]) listener();\n },\n });\n}\n\nfunction renderSlot<Props extends SlotProperties>(\n target: SlotTarget<Props>,\n fixture: SlotTestFixture<Props> = {},\n): SlotTestHarness<Props> {\n const harness = createSlotHarness(target, fixture);\n\n return Object.freeze({ Slot: harness.Slot, updateProps: harness.updateProps });\n}\n\nexport { command, createSlotHarness, renderSlot };\nexport type { SlotTestFixture, SlotTestHarness };\n","import type { RuntimeGraphSnapshot } from '@opetope/runtime/internal';\n\nimport { ScenarioTimeoutError } from './scenario-diagnostics';\nimport type { ScenarioWaitOptions } from './scenario-types';\n\nfunction positiveDuration(value: number, label: string): number {\n if (!Number.isFinite(value) || value <= 0 || value > 2_147_483_647) {\n throw new RangeError(`${label} must be a finite duration from 0 (exclusive) to 2147483647ms.`);\n }\n\n return value;\n}\n\ninterface ScenarioWaitSource {\n readonly getSnapshot: () => RuntimeGraphSnapshot;\n readonly history: () => readonly RuntimeGraphSnapshot[];\n readonly timeoutMs: number;\n}\n\nclass ScenarioWaiters {\n private readonly listeners = new Set<() => void>();\n private readonly pending = new Set<(error: Error) => void>();\n\n constructor(private readonly source: ScenarioWaitSource) {}\n\n cancel(): void {\n for (const reject of [...this.pending]) reject(new Error('Scenario is closing.'));\n }\n\n deadline<Value>(result: PromiseLike<Value>, label: string, timeoutMs = this.source.timeoutMs): Promise<Value> {\n positiveDuration(timeoutMs, 'Scenario timeoutMs');\n\n return new Promise<Value>((resolve, reject) => {\n const timer = setTimeout(() => reject(this.timeout(label, timeoutMs)), timeoutMs);\n Promise.resolve(result).then(\n value => {\n clearTimeout(timer);\n resolve(value);\n },\n (error: unknown) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n }\n\n readonly notify = (): void => {\n for (const listener of [...this.listeners]) listener();\n };\n\n waitFor(predicate: (snapshot: RuntimeGraphSnapshot) => boolean, options: ScenarioWaitOptions): Promise<void> {\n const timeoutMs = positiveDuration(options.timeoutMs ?? this.source.timeoutMs, 'Scenario timeoutMs');\n const pollIntervalMs = positiveDuration(options.pollIntervalMs ?? 10, 'Scenario pollIntervalMs');\n\n return new Promise<void>((resolve, reject) => {\n let done = false;\n let dispose = (): void => undefined;\n const finish = (error?: unknown, failed = error !== undefined): void => {\n if (done) return;\n\n done = true;\n dispose();\n\n if (!failed) resolve();\n else reject(error);\n };\n const check = (): void => {\n if (done) return;\n\n try {\n if (predicate(this.source.getSnapshot())) finish();\n } catch (error) {\n finish(error, true);\n }\n };\n const cancel = (error: Error): void => finish(error);\n const deadline = setTimeout(() => finish(this.timeout(options.label ?? 'waitFor', timeoutMs)), timeoutMs);\n const poll = setInterval(check, pollIntervalMs);\n dispose = (): void => {\n clearTimeout(deadline);\n clearInterval(poll);\n this.listeners.delete(check);\n this.pending.delete(cancel);\n };\n this.listeners.add(check);\n this.pending.add(cancel);\n check();\n });\n }\n\n private timeout(label: string, timeoutMs: number): ScenarioTimeoutError {\n return new ScenarioTimeoutError(label, timeoutMs, this.source.getSnapshot(), this.source.history());\n }\n}\n\nexport { positiveDuration, ScenarioWaiters };\n","import { createAggregateError, hasOwn } from '@opetope/core/internal';\nimport { openApplication } from '@opetope/runtime';\nimport type { Application, ApplicationConditionBinding, ApplicationExecution } from '@opetope/runtime';\nimport { createInspectionSession } from '@opetope/runtime/internal';\nimport type { OpenApplicationOptions, RuntimeGraphSnapshot, RuntimeInspectionSession } from '@opetope/runtime/internal';\n\nimport { scenarioOwnership } from './scenario-diagnostics';\nimport { ScenarioMountLease } from './scenario-mount';\nimport { createSlotHarness } from './scenario-slot';\nimport type {\n Scenario,\n ScenarioFeatures,\n ScenarioHost,\n ScenarioHostMount,\n ScenarioMount,\n ScenarioOptions,\n ScenarioWaitOptions,\n} from './scenario-types';\nimport { positiveDuration, ScenarioWaiters } from './scenario-wait';\nimport type { SlotComponentProperties, SlotProperties, SlotTarget } from './slot';\n\nfunction boundedCapacity(value: number, label: string): number {\n if (!Number.isSafeInteger(value) || value < 1 || value > 10_000) {\n throw new RangeError(`${label} must be an integer from 1 to 10000.`);\n }\n\n return value;\n}\n\nfunction validateHost(host: unknown): void {\n if (host === null || typeof host !== 'object' || !('mount' in host) || typeof host.mount !== 'function') {\n throw new TypeError('Scenario requires a host.mount(Component) adapter.');\n }\n}\n\n/**\n * What the scenario hands to `openApplication`: absence is preserved separately from an explicitly invalid value,\n * so the condition-dependent type and the D281 omissions behave exactly as they do for a host.\n */\nfunction applicationOpenOptions<const Features extends ScenarioFeatures>(\n options: ScenarioOptions<Features, ScenarioHostMount>,\n): OpenApplicationOptions<Features> {\n return {\n ...(options.cleanupFailure === undefined ? {} : { cleanupFailure: options.cleanupFailure }),\n ...(hasOwn(options, 'conditions') ? { conditions: options.conditions } : {}),\n /*\n * D366: a scenario opens a real application, so the window of a lease is the host's word here too. D407: the\n * word is the key, as it already is for `conditions` and `imports` beside it — a `grace` written as `undefined`\n * travels to `openApplication` and is refused there, instead of being dropped here into the `0` of a host that\n * wrote no window at all.\n */\n ...(hasOwn(options, 'grace') ? { grace: options.grace! } : {}),\n ...(hasOwn(options, 'imports') ? { imports: options.imports } : {}),\n reporter: options.reporter,\n };\n}\n\n/** D206: one real application, its existing inspection session and renderer-owned Slot ingress. */\nfunction createScenario<\n const Features extends ScenarioFeatures,\n Mounted extends ScenarioHostMount,\n const Bindings extends readonly ApplicationConditionBinding[] = readonly [],\n>(\n application: Application<Features>,\n options: ScenarioOptions<NoInfer<Features>, Mounted, Bindings>,\n): Scenario<Mounted> {\n const timeoutMs = positiveDuration(options.timeoutMs ?? 1_000, 'Scenario timeoutMs');\n const historyCapacity = boundedCapacity(options.historyCapacity ?? 64, 'Scenario historyCapacity');\n const activityCapacity = boundedCapacity(options.activityCapacity ?? 256, 'Scenario activityCapacity');\n let host: ScenarioHost<Mounted> | undefined = options.host;\n\n validateHost(host);\n\n let execution: ApplicationExecution | undefined = openApplication(application, applicationOpenOptions(options));\n let session: RuntimeInspectionSession;\n try {\n session = createInspectionSession(execution, { activityCapacity, ringCapacity: historyCapacity });\n } catch (error) {\n void execution.ready.catch(() => undefined);\n void execution.close().catch(() => undefined);\n throw error;\n }\n\n let phase: 'closed' | 'closing' | 'open' = 'open';\n let successfullyClosed = false;\n let capturing = false;\n const records: RuntimeGraphSnapshot[] = [];\n const mounts = new Set<ScenarioMountLease<Mounted>>();\n const mountFailures: unknown[] = [];\n const getSnapshot = (): RuntimeGraphSnapshot => session.getSnapshot();\n const history = (): readonly RuntimeGraphSnapshot[] => Object.freeze([...records]);\n const waiters = new ScenarioWaiters({ getSnapshot, history, timeoutMs });\n const capture = (): void => {\n if (capturing) return;\n\n capturing = true;\n try {\n const snapshot = getSnapshot();\n const previous = records[records.length - 1];\n\n if (previous?.stateRevision !== snapshot.stateRevision || previous.activity !== snapshot.activity) {\n records.push(snapshot);\n\n if (records.length > historyCapacity) records.shift();\n }\n } finally {\n capturing = false;\n }\n waiters.notify();\n };\n const release = session.subscribe(capture);\n capture();\n const ready = waiters.deadline(execution.ready, 'application ready');\n // A test may deliberately inspect loading without awaiting ready; rejection remains observable to that caller.\n void ready.catch(() => undefined);\n\n let physicalClose: Promise<void> | undefined;\n let closeAttempt: Promise<void> | undefined;\n const startClose = (): Promise<void> => {\n if (physicalClose !== undefined) return physicalClose;\n\n let resolve!: () => void;\n let reject!: (error: unknown) => void;\n physicalClose = new Promise<void>((accept, refuse) => {\n resolve = accept;\n reject = refuse;\n });\n phase = 'closing';\n waiters.cancel();\n const drains: Promise<void>[] = [];\n // Fence before any foreign unmount callback can reenter UI ingress; join all physical drains afterwards.\n try {\n drains.push(execution!.close());\n } catch (error) {\n drains.push(Promise.reject(error));\n }\n drains.push(...[...mounts].map(mount => mount.close()));\n void Promise.allSettled(drains).then(results => {\n const failures = [\n ...new Set([\n ...mountFailures,\n ...results.flatMap(result => (result.status === 'rejected' ? [result.reason as unknown] : [])),\n ]),\n ];\n mountFailures.length = 0;\n phase = 'closed';\n try {\n capture();\n } catch (error) {\n failures.push(error);\n } finally {\n release();\n session.close();\n mounts.clear();\n execution = undefined;\n host = undefined;\n }\n successfullyClosed = failures.length === 0;\n\n if (failures.length === 0) resolve();\n else reject(createAggregateError(failures, 'Scenario cleanup failed.'));\n });\n\n return physicalClose;\n };\n\n const close = (): Promise<void> => {\n if (closeAttempt !== undefined) return closeAttempt;\n\n const drain = startClose();\n\n // A nested close during unmount may have installed the same attempt already.\n if (closeAttempt !== undefined) return closeAttempt;\n\n closeAttempt = waiters.deadline(drain, 'scenario close');\n void closeAttempt.catch(() => {\n // A deadline cannot cancel physical work. A later close can await that same drain with a new deadline.\n if (phase === 'closing') closeAttempt = undefined;\n });\n\n return closeAttempt;\n };\n\n const mount: Scenario<Mounted>['mount'] = <Props extends SlotProperties>(\n target: SlotTarget<Props>,\n fixture: { readonly props?: SlotComponentProperties<Props> } = {},\n ): ScenarioMount<Props, Mounted> => {\n if (phase !== 'open') throw new Error('Scenario is closing.');\n\n const slot = createSlotHarness(target, fixture);\n const lease = new ScenarioMountLease<Mounted>((failed, error) => {\n mounts.delete(lease);\n slot.close();\n\n if (failed) mountFailures.push(error);\n });\n mounts.add(lease);\n let mounted: Mounted;\n try {\n mounted = host!.mount(slot.Slot);\n\n if (mounted === null || typeof mounted !== 'object' || typeof mounted.unmount !== 'function') {\n throw new TypeError('Scenario host.mount must return an unmount() handle.');\n }\n\n lease.provide(mounted);\n } catch (error) {\n lease.provide(undefined);\n void lease.close().catch(() => undefined);\n throw error;\n }\n\n return Object.freeze({\n host: mounted,\n unmount: lease.close,\n updateProps: (props: SlotComponentProperties<Props>): void => {\n if (phase !== 'open' || lease.closed) throw new Error('Scenario mount is closed.');\n\n slot.updateProps(props);\n waiters.notify();\n },\n });\n };\n\n return Object.freeze({\n close,\n getSnapshot,\n history,\n mount,\n notify: (): void => {\n if (phase === 'open') waiters.notify();\n },\n ownership: () => scenarioOwnership(getSnapshot(), successfullyClosed),\n ready,\n waitFor: (predicate: (snapshot: RuntimeGraphSnapshot) => boolean, waitOptions: ScenarioWaitOptions = {}) => {\n if (phase !== 'open') return Promise.reject(new Error('Scenario is closing.'));\n\n return waiters.waitFor(predicate, waitOptions);\n },\n });\n}\n\nexport { createScenario };\n"],"names":["instanceFacts","instance","waiting","callFact","call","blockers","activityFacts","activity","facts","feature","resource","explainSnapshot","snapshot","condition","ScenarioTimeoutError","label","timeoutMs","history","ownershipComplete","successfullyClosed","ownershipReasons","complete","reasons","ownershipCounts","scenarioOwnership","ScenarioMountLease","released","resolve","reject","handle","failed","error","testingContributionId","declarationId","command","run","bindCommand","callFixture","createSlotHarness","target","fixture","fixtures","current","listeners","props","listener","supplied","reported","fixtureAuthority","published","useReadable","slotProps","entry","contributionAuthority","contributionId","contribution","authority","createElement","ContributionMount","next","renderSlot","harness","positiveDuration","value","ScenarioWaiters","source","result","timer","predicate","options","pollIntervalMs","done","dispose","finish","check","cancel","deadline","poll","boundedCapacity","validateHost","host","applicationOpenOptions","hasOwn","createScenario","application","historyCapacity","activityCapacity","execution","openApplication","session","createInspectionSession","phase","capturing","records","mounts","mountFailures","getSnapshot","waiters","capture","previous","release","ready","physicalClose","closeAttempt","startClose","accept","refuse","drains","mount","results","failures","createAggregateError","drain","slot","lease","mounted","waitOptions"],"mappings":"+mBAIA,SAASA,EAAcC,EAA8D,CACnF,GAAIA,EAAS,MAAM,OAAS,QAAS,MAAO,CAAA,EAE5C,MAAMC,EAAUD,EAAS,MAAM,OAAS,UAAY,KAAKA,EAAS,MAAM,MAAM,IAAM,GAEpF,MAAO,CAAC,WAAWA,EAAS,KAAK,KAAKA,EAAS,MAAM,IAAI,GAAGC,CAAO,GAAG,CACxE,CAEA,SAASC,EAASC,EAA8C,CAC9D,GAAIA,EAAK,OAAS,KAAM,MAAO,WAAWA,EAAK,WAAW,KAAKA,EAAK,KAAK,6CAEzE,MAAMC,EAAWD,EAAK,KAAK,YAAc,UAAY,UAAYA,EAAK,KAAK,UAAU,KAAK,IAAI,EAE9F,MAAO,WAAWA,EAAK,WAAW,KAAKA,EAAK,KAAK,UAAUA,EAAK,KAAK,WAAW,cAAcC,CAAQ,GACxG,CAEA,SAASC,EAAcC,EAA6C,CAClE,GAAIA,IAAa,OAAW,MAAO,CAAC,4BAA4B,EAEhE,MAAMC,EAAkB,CAAA,EAExB,OAAID,EAAS,YAAc,SAAWA,EAAS,YAC7CC,EAAM,KAAK,aAAaD,EAAS,SAAS,GAAGA,EAAS,UAAY,cAAgB,EAAE,yBAAyB,EAGxG,CACL,GAAGC,EACH,GAAGD,EAAS,SAAS,IACnBE,GAAW,WAAWA,EAAQ,OAAO,KAAKA,EAAQ,KAAK,UAAUA,EAAQ,IAAI,wBAAwB,EAEvG,GAAGF,EAAS,MAAM,IAAIJ,CAAQ,EAC9B,GAAGI,EAAS,UAAU,IACpBG,GAAY,YAAYA,EAAS,EAAE,KAAKA,EAAS,KAAK,YAAY,OAAOA,EAAS,MAAM,CAAC,GAAG,EAGlG,CAEA,SAASC,EAAgBC,EAA8B,CACrD,MAAMJ,EAAQ,CACZ,GAAGI,EAAS,QAAQ,WAAW,QAAQC,GACrCA,EAAU,MAAM,OAAS,OAAS,CAAA,EAAK,CAAC,aAAaA,EAAU,KAAK,KAAKA,EAAU,MAAM,IAAI,GAAG,CAAC,EAEnG,GAAGD,EAAS,QAAQ,UAAU,QAAQZ,CAAa,EACnD,GAAGM,EAAcM,EAAS,QAAQ,GAGpC,OAAOJ,EAAM,SAAW,EACpB,iFACAA,EAAM,KAAK;AAAA,CAAI,CACrB,CAGA,MAAMM,UAA6B,KAAK,CAI3B,MACA,UACA,SACA,QANF,KAAO,UAEhB,YACWC,EACAC,EACAJ,EACAK,EAAwC,CAEjD,MAAM,4BAA4B,OAAOD,CAAS,CAAC,OAAOD,CAAK;AAAA,EAAMJ,EAAgBC,CAAQ,CAAC,EAAE,EALvF,KAAA,MAAAG,EACA,KAAA,UAAAC,EACA,KAAA,SAAAJ,EACA,KAAA,QAAAK,EAGT,KAAK,KAAO,sBACd,CACD,CAED,SAASC,EAAkBX,EAA+CY,EAA2B,CACnG,MAAI,CAACA,GAAsBZ,IAAa,OAAkB,GAEnDA,EAAS,QAAU,CAACA,EAAS,SACtC,CAEA,SAASa,EACPb,EACAc,EACAF,EAA2B,CAE3B,GAAIZ,IAAa,OAAW,MAAO,CAAC,kCAAkC,EAEtE,MAAMe,EAAoB,CAAA,EAE1B,OAAIf,EAAS,WAAWe,EAAQ,KAAK,qCAAqC,EAEtEf,EAAS,YAAc,SAAW,CAACc,GAAUC,EAAQ,KAAK,iCAAiC,EAE1FH,GAAoBG,EAAQ,KAAK,iEAAiE,EAEhG,OAAO,OAAOA,CAAO,CAC9B,CAEA,SAASC,EACPhB,EACAc,EAAiB,CAEjB,OAAId,IAAa,QAAaA,EAAS,WAAcA,EAAS,YAAc,SAAW,CAACc,EAC/E,CAAE,MAAO,UAAW,SAAU,UAAW,UAAW,SAAS,EAG/D,CAAE,MAAOd,EAAS,MAAM,OAAQ,SAAUA,EAAS,SAAS,OAAQ,UAAWA,EAAS,UAAU,MAAM,CACjH,CAEA,SAASiB,EAAkBZ,EAAgCO,EAA2B,CACpF,MAAMZ,EAAWK,EAAS,SACpBS,EAAWH,EAAkBX,EAAUY,CAAkB,EAE/D,OAAO,OAAO,OAAO,CACnB,GAAGI,EAAgBhB,EAAUc,CAAQ,EACrC,OAAQF,EACR,QAASC,EAAiBb,EAAUc,EAAUF,CAAkB,EAChE,MAAO,qBACP,OAAQE,EAAW,WAAa,SACjC,CAAA,CACH,CCjHA,MAAMI,CAAkB,CAWO,SAV7B,IAAI,QAAM,CACR,OAAO,KAAK,aAAe,MAC7B,CACQ,UAAY,GACZ,WACA,OACA,OAEA,QAER,YAA6BC,EAAoD,CAApD,KAAA,SAAAA,CAAuD,CAE3E,MAAQ,IACX,KAAK,aAAe,OAAkB,KAAK,YAE/C,KAAK,WAAa,IAAI,QAAc,CAACC,EAASC,IAAU,CACtD,KAAK,QAAUD,EACf,KAAK,OAASC,CAChB,CAAC,EAEG,KAAK,WAAW,KAAK,iBAAgB,EAElC,KAAK,YAGd,QAAQC,EAA2B,CACjC,KAAK,UAAY,GACjB,KAAK,OAASA,EAEV,KAAK,QAAQ,KAAK,iBAAgB,CACxC,CAEQ,OAAOC,EAAiBC,EAAe,CAC7C,MAAMJ,EAAU,KAAK,QACfC,EAAS,KAAK,OACpB,KAAK,QAAU,OACf,KAAK,OAAS,OACd,KAAK,SAASE,EAAQC,CAAK,EAEtBD,EACAF,GAAA,MAAAA,EAASG,GADDJ,GAAA,MAAAA,GAEf,CAEQ,kBAAgB,CACtB,MAAME,EAAS,KAAK,OACpB,KAAK,OAAS,OACd,KAAK,UAAY,GACjB,GAAI,CACF,QAAQ,QAAQA,GAAA,YAAAA,EAAQ,SAAS,EAAE,KACjC,IAAM,KAAK,OAAO,EAAK,EACtBE,GAAmB,KAAK,OAAO,GAAMA,CAAK,CAAC,CAEhD,OAASA,EAAO,CACd,KAAK,OAAO,GAAMA,CAAK,CACzB,CACF,CACD,CC3BD,MAAMC,GAAwBC,EAAc,sBAAsB,EAOlE,SAASC,GACPC,EAAuG,CAEvG,OAAOC,EAAYC,EAA2BF,CAAG,CAAC,CACpD,CAMA,SAASG,EACPC,EACAC,EAAkC,GAAE,CAEpC,MAAMC,EAAWD,EAAQ,QAAU,CAAA,EACnC,IAAIE,EAAkBF,EAAQ,OAAS,CAAA,EACvC,MAAMG,EAAY,IAAI,IAChBC,EAAQ,CACZ,YAAa,IAAcF,EAC3B,UAAYG,IACVF,EAAU,IAAIE,CAAQ,EAEf,IAAMF,EAAU,OAAOE,CAAQ,IAIpCC,EAAWN,EAAQ,aACnBO,EAAWP,EAAQ,SACnBQ,EAAmBD,IAAa,OAAY,OAAY,CAAE,OAAQ,CAAA,EAAI,SAAUA,CAAQ,EAyB9F,OAAO,OAAO,OAAO,CACnB,MAAO,IAAW,CAChBL,EAAU,CAAA,EACVC,EAAU,MAAK,CACjB,EACA,KA7BkB,IAAgB,CAClC,MAAMM,EAAYC,EAAYX,EAAO,OAAO,EACtCY,EAAYD,EAAYN,CAAK,EASnC,OAPEE,IAAa,OACTG,EAAU,IACRG,GACE,CAACA,EAAM,GAAIA,EAAM,MAA4BC,EAAsBD,CAAK,GAAKJ,CAAgB,CAAU,EAE3G,CAAC,CAAChB,GAAuBc,EAA0CE,CAAgB,CAAU,GAEpF,IAAI,CAAC,CAACM,EAAgBC,EAAcC,CAAS,IAC1DC,EAAcC,EAAmB,CAC/B,UAAAF,EACA,aAAAD,EACA,eAAAD,EACA,SAAAb,EACA,IAAKa,EACL,UAAAH,EACA,SAAUZ,EAAO,EAClB,CAAA,CAAC,CAEN,EAQE,YAAcoB,GAA8C,CAC1DjB,EAAUiB,EAEV,UAAWd,IAAY,CAAC,GAAGF,CAAS,EAAGE,EAAQ,CACjD,CACD,CAAA,CACH,CAEA,SAASe,GACPrB,EACAC,EAAkC,GAAE,CAEpC,MAAMqB,EAAUvB,EAAkBC,EAAQC,CAAO,EAEjD,OAAO,OAAO,OAAO,CAAE,KAAMqB,EAAQ,KAAM,YAAaA,EAAQ,YAAa,CAC/E,CC7GA,SAASC,EAAiBC,EAAehD,EAAa,CACpD,GAAI,CAAC,OAAO,SAASgD,CAAK,GAAKA,GAAS,GAAKA,EAAQ,WACnD,MAAM,IAAI,WAAW,GAAGhD,CAAK,gEAAgE,EAG/F,OAAOgD,CACT,CAQA,MAAMC,EAAe,CAIU,OAHZ,UAAY,IAAI,IAChB,QAAU,IAAI,IAE/B,YAA6BC,EAA0B,CAA1B,KAAA,OAAAA,CAA6B,CAE1D,QAAM,CACJ,UAAWrC,IAAU,CAAC,GAAG,KAAK,OAAO,EAAGA,EAAO,IAAI,MAAM,sBAAsB,CAAC,CAClF,CAEA,SAAgBsC,EAA4BnD,EAAeC,EAAY,KAAK,OAAO,UAAS,CAC1F,OAAA8C,EAAiB9C,EAAW,oBAAoB,EAEzC,IAAI,QAAe,CAACW,EAASC,IAAU,CAC5C,MAAMuC,EAAQ,WAAW,IAAMvC,EAAO,KAAK,QAAQb,EAAOC,CAAS,CAAC,EAAGA,CAAS,EAChF,QAAQ,QAAQkD,CAAM,EAAE,KACtBH,GAAQ,CACN,aAAaI,CAAK,EAClBxC,EAAQoC,CAAK,CACf,EACChC,GAAkB,CACjB,aAAaoC,CAAK,EAClBvC,EAAOG,CAAK,CACd,CAAC,CAEL,CAAC,CACH,CAES,OAAS,IAAW,CAC3B,UAAWc,IAAY,CAAC,GAAG,KAAK,SAAS,EAAGA,EAAQ,CACtD,EAEA,QAAQuB,EAAwDC,EAA4B,CAC1F,MAAMrD,EAAY8C,EAAiBO,EAAQ,WAAa,KAAK,OAAO,UAAW,oBAAoB,EAC7FC,EAAiBR,EAAiBO,EAAQ,gBAAkB,GAAI,yBAAyB,EAE/F,OAAO,IAAI,QAAc,CAAC1C,EAASC,IAAU,CAC3C,IAAI2C,EAAO,GACPC,EAAU,IAAA,GACd,MAAMC,EAAS,CAAC1C,EAAiBD,EAASC,IAAU,SAAmB,CACjEwC,IAEJA,EAAO,GACPC,EAAO,EAEF1C,EACAF,EAAOG,CAAK,EADJJ,EAAO,EAEtB,EACM+C,EAAQ,IAAW,CACvB,GAAI,CAAAH,EAEJ,GAAI,CACEH,EAAU,KAAK,OAAO,YAAW,CAAE,GAAGK,EAAM,CAClD,OAAS1C,EAAO,CACd0C,EAAO1C,EAAO,EAAI,CACpB,CACF,EACM4C,EAAU5C,GAAuB0C,EAAO1C,CAAK,EAC7C6C,EAAW,WAAW,IAAMH,EAAO,KAAK,QAAQJ,EAAQ,OAAS,UAAWrD,CAAS,CAAC,EAAGA,CAAS,EAClG6D,EAAO,YAAYH,EAAOJ,CAAc,EAC9CE,EAAU,IAAW,CACnB,aAAaI,CAAQ,EACrB,cAAcC,CAAI,EAClB,KAAK,UAAU,OAAOH,CAAK,EAC3B,KAAK,QAAQ,OAAOC,CAAM,CAC5B,EACA,KAAK,UAAU,IAAID,CAAK,EACxB,KAAK,QAAQ,IAAIC,CAAM,EACvBD,EAAK,CACP,CAAC,CACH,CAEQ,QAAQ3D,EAAeC,EAAiB,CAC9C,OAAO,IAAIF,EAAqBC,EAAOC,EAAW,KAAK,OAAO,cAAe,KAAK,OAAO,QAAO,CAAE,CACpG,CACD,CCzED,SAAS8D,EAAgBf,EAAehD,EAAa,CACnD,GAAI,CAAC,OAAO,cAAcgD,CAAK,GAAKA,EAAQ,GAAKA,EAAQ,IACvD,MAAM,IAAI,WAAW,GAAGhD,CAAK,sCAAsC,EAGrE,OAAOgD,CACT,CAEA,SAASgB,GAAaC,EAAa,CACjC,GAAIA,IAAS,MAAQ,OAAOA,GAAS,UAAY,EAAE,UAAWA,IAAS,OAAOA,EAAK,OAAU,WAC3F,MAAM,IAAI,UAAU,oDAAoD,CAE5E,CAMA,SAASC,GACPZ,EAAqD,CAErD,MAAO,CACL,GAAIA,EAAQ,iBAAmB,OAAY,CAAA,EAAK,CAAE,eAAgBA,EAAQ,gBAC1E,GAAIa,EAAOb,EAAS,YAAY,EAAI,CAAE,WAAYA,EAAQ,UAAU,EAAK,GAOzE,GAAIa,EAAOb,EAAS,OAAO,EAAI,CAAE,MAAOA,EAAQ,KAAM,EAAK,GAC3D,GAAIa,EAAOb,EAAS,SAAS,EAAI,CAAE,QAASA,EAAQ,OAAO,EAAK,GAChE,SAAUA,EAAQ,SAEtB,CAGA,SAASc,GAKPC,EACAf,EAA8D,CAE9D,MAAMrD,EAAY8C,EAAiBO,EAAQ,WAAa,IAAO,oBAAoB,EAC7EgB,EAAkBP,EAAgBT,EAAQ,iBAAmB,GAAI,0BAA0B,EAC3FiB,EAAmBR,EAAgBT,EAAQ,kBAAoB,IAAK,2BAA2B,EACrG,IAAIW,EAA0CX,EAAQ,KAEtDU,GAAaC,CAAI,EAEjB,IAAIO,EAA8CC,EAAgBJ,EAAaH,GAAuBZ,CAAO,CAAC,EAC1GoB,EACJ,GAAI,CACFA,EAAUC,EAAwBH,EAAW,CAAE,iBAAAD,EAAkB,aAAcD,EAAiB,CAClG,OAAStD,EAAO,CACd,MAAKwD,EAAU,MAAM,MAAM,IAAA,EAAe,EACrCA,EAAU,MAAK,EAAG,MAAM,IAAA,EAAe,EACtCxD,CACR,CAEA,IAAI4D,EAAuC,OACvCxE,EAAqB,GACrByE,EAAY,GAChB,MAAMC,EAAkC,CAAA,EAClCC,EAAS,IAAI,IACbC,EAA2B,CAAA,EAC3BC,EAAc,IAA4BP,EAAQ,YAAW,EAC7DxE,EAAU,IAAuC,OAAO,OAAO,CAAC,GAAG4E,CAAO,CAAC,EAC3EI,EAAU,IAAIjC,GAAgB,CAAE,YAAAgC,EAAa,QAAA/E,EAAS,UAAAD,EAAW,EACjEkF,EAAU,IAAW,CACzB,GAAI,CAAAN,EAEJ,CAAAA,EAAY,GACZ,GAAI,CACF,MAAMhF,EAAWoF,EAAW,EACtBG,EAAWN,EAAQA,EAAQ,OAAS,CAAC,IAEvCM,GAAA,YAAAA,EAAU,iBAAkBvF,EAAS,eAAiBuF,EAAS,WAAavF,EAAS,YACvFiF,EAAQ,KAAKjF,CAAQ,EAEjBiF,EAAQ,OAASR,GAAiBQ,EAAQ,MAAK,EAEvD,SACED,EAAY,EACd,CACAK,EAAQ,OAAM,EAChB,EACMG,EAAUX,EAAQ,UAAUS,CAAO,EACzCA,EAAO,EACP,MAAMG,EAAQJ,EAAQ,SAASV,EAAU,MAAO,mBAAmB,EAE9Dc,EAAM,MAAM,IAAA,EAAe,EAEhC,IAAIC,EACAC,EACJ,MAAMC,EAAa,IAAoB,CACrC,GAAIF,IAAkB,OAAW,OAAOA,EAExC,IAAI3E,EACAC,EACJ0E,EAAgB,IAAI,QAAc,CAACG,EAAQC,IAAU,CACnD/E,EAAU8E,EACV7E,EAAS8E,CACX,CAAC,EACDf,EAAQ,UACRM,EAAQ,OAAM,EACd,MAAMU,EAA0B,CAAA,EAEhC,GAAI,CACFA,EAAO,KAAKpB,EAAW,OAAO,CAChC,OAASxD,EAAO,CACd4E,EAAO,KAAK,QAAQ,OAAO5E,CAAK,CAAC,CACnC,CACA,OAAA4E,EAAO,KAAK,GAAG,CAAC,GAAGb,CAAM,EAAE,IAAIc,GAASA,EAAM,MAAK,CAAE,CAAC,EACjD,QAAQ,WAAWD,CAAM,EAAE,KAAKE,GAAU,CAC7C,MAAMC,EAAW,CACf,GAAG,IAAI,IAAI,CACT,GAAGf,EACH,GAAGc,EAAQ,QAAQ3C,GAAWA,EAAO,SAAW,WAAa,CAACA,EAAO,MAAiB,EAAI,CAAA,CAAG,EAC9F,GAEH6B,EAAc,OAAS,EACvBJ,EAAQ,SACR,GAAI,CACFO,EAAO,CACT,OAASnE,EAAO,CACd+E,EAAS,KAAK/E,CAAK,CACrB,SACEqE,EAAO,EACPX,EAAQ,MAAK,EACbK,EAAO,MAAK,EACZP,EAAY,OACZP,EAAO,MACT,CACA7D,EAAqB2F,EAAS,SAAW,EAErCA,EAAS,SAAW,EAAGnF,EAAO,EAC7BC,EAAOmF,EAAqBD,EAAU,0BAA0B,CAAC,CACxE,CAAC,EAEMR,CACT,EA4DA,OAAO,OAAO,OAAO,CACnB,MA3DY,IAAoB,CAChC,GAAIC,IAAiB,OAAW,OAAOA,EAEvC,MAAMS,EAAQR,EAAU,EAGxB,OAAID,IAAiB,SAErBA,EAAeN,EAAQ,SAASe,EAAO,gBAAgB,EAClDT,EAAa,MAAM,IAAK,CAEvBZ,IAAU,YAAWY,EAAe,OAC1C,CAAC,GAEMA,CACT,EA6CE,YAAAP,EACA,QAAA/E,EACA,MA7CwC,CACxCsB,EACAC,EAA+D,CAAA,IAC9B,CACjC,GAAImD,IAAU,OAAQ,MAAM,IAAI,MAAM,sBAAsB,EAE5D,MAAMsB,EAAO3E,EAAkBC,EAAQC,CAAO,EACxC0E,EAAQ,IAAIzF,EAA4B,CAACK,EAAQC,IAAS,CAC9D+D,EAAO,OAAOoB,CAAK,EACnBD,EAAK,MAAK,EAENnF,GAAQiE,EAAc,KAAKhE,CAAK,CACtC,CAAC,EACD+D,EAAO,IAAIoB,CAAK,EAChB,IAAIC,EACJ,GAAI,CAGF,GAFAA,EAAUnC,EAAM,MAAMiC,EAAK,IAAI,EAE3BE,IAAY,MAAQ,OAAOA,GAAY,UAAY,OAAOA,EAAQ,SAAY,WAChF,MAAM,IAAI,UAAU,sDAAsD,EAG5ED,EAAM,QAAQC,CAAO,CACvB,OAASpF,EAAO,CACd,MAAAmF,EAAM,QAAQ,MAAS,EAClBA,EAAM,MAAK,EAAG,MAAM,IAAA,EAAe,EAClCnF,CACR,CAEA,OAAO,OAAO,OAAO,CACnB,KAAMoF,EACN,QAASD,EAAM,MACf,YAActE,GAA+C,CAC3D,GAAI+C,IAAU,QAAUuB,EAAM,OAAQ,MAAM,IAAI,MAAM,2BAA2B,EAEjFD,EAAK,YAAYrE,CAAK,EACtBqD,EAAQ,OAAM,CAChB,CACD,CAAA,CACH,EAOE,OAAQ,IAAW,CACbN,IAAU,QAAQM,EAAQ,OAAM,CACtC,EACA,UAAW,IAAMzE,EAAkBwE,EAAW,EAAI7E,CAAkB,EACpE,MAAAkF,EACA,QAAS,CAACjC,EAAwDgD,EAAmC,KAC/FzB,IAAU,OAAe,QAAQ,OAAO,IAAI,MAAM,sBAAsB,CAAC,EAEtEM,EAAQ,QAAQ7B,EAAWgD,CAAW,CAEhD,CAAA,CACH"}
|
|
1
|
+
{"version":3,"file":"testing.js","sources":["../src/scenario-diagnostics.ts","../src/scenario-mount.ts","../src/scenario-slot.tsx","../src/scenario-wait.ts","../src/scenario.ts"],"sourcesContent":["import type { RuntimeActivitySnapshot, RuntimeGraphSnapshot } from '@opetope/runtime/internal';\n\nimport type { ScenarioOwnership } from './scenario-types';\n\nfunction instanceFacts(instance: RuntimeGraphSnapshot['runtime']['instances'][number]): readonly string[] {\n if (instance.state.kind === 'ready') return [];\n\n const waiting = instance.state.kind === 'waiting' ? ` (${instance.state.reason})` : '';\n\n return [`Feature ${instance.label}: ${instance.state.kind}${waiting}.`];\n}\n\nfunction callFact(call: RuntimeActivitySnapshot['calls'][number]): string {\n if (call.lane === null) return `Command ${call.declaration}: ${call.state}; lane parallel; blockers none (parallel).`;\n\n const blockers = call.lane.blockedBy === 'unknown' ? 'unknown' : call.lane.blockedBy.join(', ');\n\n return `Command ${call.declaration}: ${call.state}; lane ${call.lane.declaration}; blockers ${blockers}.`;\n}\n\nfunction activityFacts(activity: RuntimeActivitySnapshot | undefined): readonly string[] {\n if (activity === undefined) return ['Runtime activity: unknown.'];\n\n const facts: string[] = [];\n\n if (activity.freshness === 'stale' || activity.truncated) {\n facts.push(`Activity: ${activity.freshness}${activity.truncated ? ', truncated' : ''}; completeness unknown.`);\n }\n\n return [\n ...facts,\n ...activity.features.map(\n feature => `Feature ${feature.feature}: ${feature.phase}; body ${feature.body}; host demand unknown.`,\n ),\n ...activity.calls.map(callFact),\n ...activity.resources.map(\n resource => `Resource ${resource.id}: ${resource.state}; leases ${String(resource.leases)}.`,\n ),\n ];\n}\n\nfunction explainSnapshot(snapshot: RuntimeGraphSnapshot): string {\n const facts = [\n ...snapshot.runtime.conditions.flatMap(condition =>\n condition.state.kind === 'true' ? [] : [`Condition ${condition.label}: ${condition.state.kind}.`],\n ),\n ...snapshot.runtime.instances.flatMap(instanceFacts),\n ...activityFacts(snapshot.activity),\n ];\n\n return facts.length === 0\n ? 'No registered runtime blocker observed; external UI and host work are unknown.'\n : facts.join('\\n');\n}\n\n/* D206: the failure carries the producer's same data-only graph/activity facts, without product payloads. */\n/**\n * The failure carries the producer's same data-only graph/activity facts, without product payloads.\n */\nclass ScenarioTimeoutError extends Error {\n readonly code = 'timeout';\n\n constructor(\n readonly label: string,\n readonly timeoutMs: number,\n readonly snapshot: RuntimeGraphSnapshot,\n readonly history: readonly RuntimeGraphSnapshot[],\n ) {\n super(`Scenario timed out after ${String(timeoutMs)}ms: ${label}.\\n${explainSnapshot(snapshot)}`);\n this.name = 'ScenarioTimeoutError';\n }\n}\n\nfunction ownershipComplete(activity: RuntimeActivitySnapshot | undefined, successfullyClosed: boolean): boolean {\n if (!successfullyClosed || activity === undefined) return false;\n\n return activity.closed && !activity.truncated;\n}\n\nfunction ownershipReasons(\n activity: RuntimeActivitySnapshot | undefined,\n complete: boolean,\n successfullyClosed: boolean,\n): readonly string[] {\n if (activity === undefined) return ['Runtime activity is unavailable.'];\n\n const reasons: string[] = [];\n\n if (activity.truncated) reasons.push('The activity snapshot is truncated.');\n\n if (activity.freshness === 'stale' && !complete) reasons.push('The activity snapshot is stale.');\n\n if (!successfullyClosed) reasons.push('Successful application and mount cleanup has not been observed.');\n\n return Object.freeze(reasons);\n}\n\nfunction ownershipCounts(\n activity: RuntimeActivitySnapshot | undefined,\n complete: boolean,\n): Pick<ScenarioOwnership, 'calls' | 'features' | 'resources'> {\n if (activity === undefined || activity.truncated || (activity.freshness === 'stale' && !complete)) {\n return { calls: 'unknown', features: 'unknown', resources: 'unknown' };\n }\n\n return { calls: activity.calls.length, features: activity.features.length, resources: activity.resources.length };\n}\n\nfunction scenarioOwnership(snapshot: RuntimeGraphSnapshot, successfullyClosed: boolean): ScenarioOwnership {\n const activity = snapshot.activity;\n const complete = ownershipComplete(activity, successfullyClosed);\n\n return Object.freeze({\n ...ownershipCounts(activity, complete),\n closed: successfullyClosed,\n reasons: ownershipReasons(activity, complete, successfullyClosed),\n scope: 'registered-runtime',\n status: complete ? 'complete' : 'unknown',\n });\n}\n\nexport { scenarioOwnership, ScenarioTimeoutError };\n","import { actNow } from './act-delivery';\nimport type { ScenarioHostMount } from './scenario-types';\n\n/** A reservation exists before the host callback, so reentrant close also owns a mount returned later. */\nclass ScenarioMountLease<Mounted extends ScenarioHostMount> {\n get closed(): boolean {\n return this.completion !== undefined;\n }\n private available = false;\n private completion: Promise<void> | undefined;\n private handle: Mounted | undefined;\n private reject: ((error: unknown) => void) | undefined;\n\n private resolve: (() => void) | undefined;\n\n constructor(\n private readonly released: (failed: boolean, error?: unknown) => void,\n private readonly act: ((callback: () => unknown) => PromiseLike<unknown>) | undefined,\n ) {}\n\n readonly close = (): Promise<void> => {\n if (this.completion !== undefined) return this.completion;\n\n this.completion = new Promise<void>((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n\n if (this.available) this.releaseAvailable();\n\n return this.completion;\n };\n\n provide(handle: Mounted | undefined): void {\n this.available = true;\n this.handle = handle;\n\n if (this.closed) this.releaseAvailable();\n }\n\n private finish(failed: boolean, error?: unknown): void {\n const resolve = this.resolve;\n const reject = this.reject;\n this.resolve = undefined;\n this.reject = undefined;\n this.released(failed, error);\n\n if (!failed) resolve?.();\n else reject?.(error);\n }\n\n private releaseAvailable(): void {\n const handle = this.handle;\n this.handle = undefined;\n this.available = false;\n try {\n const unmount = (): unknown => handle?.unmount();\n // D541: an unmount inside the renderer's act, so the cleanup it commits is flushed before `unmount` answers.\n Promise.resolve(this.act === undefined ? unmount() : actNow(this.act, unmount)).then(\n () => this.finish(false),\n (error: unknown) => this.finish(true, error),\n );\n } catch (error) {\n this.finish(true, error);\n }\n }\n}\n\nexport { ScenarioMountLease };\n","import { createElement } from 'react';\nimport type { FC, ReactNode } from 'react';\n\nimport { declarationId } from '@opetope/core';\n\nimport { contributionAuthority, ContributionMount } from './contribution-frame';\nimport type { ContributionValue, ModelFixture } from './contribution-frame';\nimport { useReadable } from './readable-hooks';\nimport type { SlotComponentProperties, SlotContribution, SlotProperties, SlotTarget } from './slot';\n\n/*\n * Two forms, as `renderRoot` had (D19): without `contribution` the harness mounts what the target published, with it\n * the harness mounts one fixture contribution so a component test needs no generation.\n */\n/**\n * Two forms, as `renderRoot` had: without `contribution` the harness mounts what the target published.\n */\ntype SlotTestFixture<Props extends SlotProperties> = {\n readonly contribution?: SlotContribution<Props>;\n readonly models?: readonly ModelFixture[];\n readonly props?: SlotComponentProperties<Props>;\n /*\n * Where a contained mount failure is reported (D256). A component test has no feature to report to, so without it\n * the failure is detached and the assertion has nothing to read.\n */\n /**\n * Where a contained mount failure is reported.\n */\n readonly reporter?: (error: unknown) => void;\n};\n\ninterface SlotTestHarness<Props extends SlotProperties> {\n readonly Slot: FC;\n readonly updateProps: (props: SlotComponentProperties<Props>) => void;\n}\n\nconst testingContributionId = declarationId('testing.contribution');\n\n/**\n * Mounts the contributions of one slot the way a host does, with optional model fixtures for a component test. D19 and D85: the same\n * ContributionMount is shared by component tests and the application scenario harness (D206).\n */\nfunction createSlotHarness<Props extends SlotProperties>(\n target: SlotTarget<Props>,\n fixture: SlotTestFixture<Props> = {},\n): SlotTestHarness<Props> & { readonly close: () => void } {\n const fixtures = fixture.models ?? [];\n let current: object = fixture.props ?? {};\n const listeners = new Set<() => void>();\n const props = {\n getSnapshot: (): object => current,\n subscribe: (listener: () => void): (() => void) => {\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n },\n };\n\n const supplied = fixture.contribution;\n const reported = fixture.reporter;\n const fixtureAuthority = reported === undefined ? undefined : { models: [], reporter: reported };\n const Mounted: FC = (): ReactNode => {\n const published = useReadable(target.entries);\n const slotProps = useReadable(props);\n const entries =\n supplied === undefined\n ? published.map(\n entry =>\n [entry.id, entry.value as ContributionValue, contributionAuthority(entry) ?? fixtureAuthority] as const,\n )\n : [[testingContributionId, supplied as unknown as ContributionValue, fixtureAuthority] as const];\n\n return entries.map(([contributionId, contribution, authority]) =>\n createElement(ContributionMount, {\n authority,\n contribution,\n contributionId,\n fixtures,\n key: contributionId,\n slotProps,\n targetId: target.id,\n }),\n );\n };\n\n return Object.freeze({\n close: (): void => {\n current = {};\n listeners.clear();\n },\n Slot: Mounted,\n updateProps: (next: SlotComponentProperties<Props>): void => {\n current = next;\n\n for (const listener of [...listeners]) listener();\n },\n });\n}\n\n/**\n * Mounts one slot contribution under the React test harness.\n */\nfunction renderSlot<Props extends SlotProperties>(\n target: SlotTarget<Props>,\n fixture: SlotTestFixture<Props> = {},\n): SlotTestHarness<Props> {\n const harness = createSlotHarness(target, fixture);\n\n return Object.freeze({ Slot: harness.Slot, updateProps: harness.updateProps });\n}\n\nexport { createSlotHarness, renderSlot };\nexport type { SlotTestFixture, SlotTestHarness };\n","import type { RuntimeGraphSnapshot } from '@opetope/runtime/internal';\n\nimport { ScenarioTimeoutError } from './scenario-diagnostics';\nimport type { ScenarioWaitOptions } from './scenario-types';\n\nfunction positiveDuration(value: number, label: string): number {\n if (!Number.isFinite(value) || value <= 0 || value > 2_147_483_647) {\n throw new RangeError(`${label} must be a finite duration from 0 (exclusive) to 2147483647ms.`);\n }\n\n return value;\n}\n\ninterface ScenarioWaitSource {\n readonly getSnapshot: () => RuntimeGraphSnapshot;\n readonly history: () => readonly RuntimeGraphSnapshot[];\n readonly timeoutMs: number;\n}\n\ntype ScenarioWaitRead =\n | { readonly kind: 'source'; readonly read: () => unknown }\n | { readonly kind: 'graph'; readonly read: (snapshot: RuntimeGraphSnapshot) => unknown };\n\nclass ScenarioWaiters {\n private readonly listeners = new Set<() => void>();\n private readonly pending = new Set<(error: Error) => void>();\n\n constructor(private readonly source: ScenarioWaitSource) {}\n\n cancel(): void {\n for (const reject of [...this.pending]) reject(new Error('Scenario is closing.'));\n }\n\n deadline<Value>(result: PromiseLike<Value>, label: string, timeoutMs = this.source.timeoutMs): Promise<Value> {\n positiveDuration(timeoutMs, 'Scenario timeoutMs');\n\n return new Promise<Value>((resolve, reject) => {\n const timer = setTimeout(() => reject(this.timeout(label, timeoutMs)), timeoutMs);\n Promise.resolve(result).then(\n value => {\n clearTimeout(timer);\n resolve(value);\n },\n (error: unknown) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n }\n\n readonly notify = (): void => {\n for (const listener of [...this.listeners]) listener();\n };\n\n waitFor(\n request: ScenarioWaitRead,\n accept: ((value: unknown) => boolean) | undefined,\n options: ScenarioWaitOptions,\n ): Promise<unknown> {\n const timeoutMs = positiveDuration(options.timeoutMs ?? this.source.timeoutMs, 'Scenario timeoutMs');\n const pollIntervalMs = positiveDuration(options.pollIntervalMs ?? 10, 'Scenario pollIntervalMs');\n const readValue = request.kind === 'source' ? request.read : () => request.read(this.source.getSnapshot());\n const synchronous = (value: unknown, half: 'reads' | 'decides'): unknown => {\n if (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof Reflect.get(value, 'then') === 'function'\n ) {\n throw new TypeError(`Scenario.waitFor ${half} synchronously; put an awaited read inside eventually.`);\n }\n return value;\n };\n\n return new Promise<unknown>((resolve, reject) => {\n let done = false;\n let dispose = (): void => undefined;\n const finish = (value: unknown, failed = false): void => {\n if (done) return;\n done = true;\n dispose();\n if (failed) reject(value);\n else resolve(value);\n };\n const check = (): void => {\n if (done) return;\n try {\n const value = synchronous(readValue(), 'reads');\n const accepted =\n accept === undefined\n ? value !== false && value !== null && value !== undefined\n : synchronous(accept(value), 'decides');\n if (accepted) finish(value);\n } catch (error) {\n finish(error, true);\n }\n };\n const cancel = (error: Error): void => finish(error, true);\n const deadline = setTimeout(\n () =>\n finish(\n this.timeout(options.label ?? (request.kind === 'source' ? 'waitFor(source)' : 'waitFor'), timeoutMs),\n true,\n ),\n timeoutMs,\n );\n const poll = setInterval(check, pollIntervalMs);\n dispose = (): void => {\n clearTimeout(deadline);\n clearInterval(poll);\n this.listeners.delete(check);\n this.pending.delete(cancel);\n };\n this.listeners.add(check);\n this.pending.add(cancel);\n check();\n });\n }\n\n private timeout(label: string, timeoutMs: number): ScenarioTimeoutError {\n return new ScenarioTimeoutError(label, timeoutMs, this.source.getSnapshot(), this.source.history());\n }\n}\n\nexport { positiveDuration, ScenarioWaiters };\n","import type { Readable, ResourceView } from '@opetope/core';\nimport { createAggregateError, hasOwn, isResourceView } from '@opetope/core/internal';\nimport { openApplication } from '@opetope/runtime';\nimport type {\n Application,\n ApplicationConditionBinding,\n ApplicationExecution,\n ApplicationImportBinding,\n ErrorReporter,\n} from '@opetope/runtime';\nimport { createInspectionSession, testingTimeoutMs } from '@opetope/runtime/internal';\nimport type { OpenApplicationOptions, RuntimeGraphSnapshot, RuntimeInspectionSession } from '@opetope/runtime/internal';\n\nimport { actNow, installAct } from './act-delivery';\nimport type { ActFunction } from './act-delivery';\nimport { scenarioOwnership } from './scenario-diagnostics';\nimport { ScenarioMountLease } from './scenario-mount';\nimport { createSlotHarness } from './scenario-slot';\nimport type {\n Scenario,\n ScenarioFeatures,\n ScenarioHost,\n ScenarioHostMount,\n ScenarioMount,\n ScenarioOptions,\n ScenarioReadWithoutAccept,\n ScenarioWaitOptions,\n} from './scenario-types';\nimport { positiveDuration, ScenarioWaiters } from './scenario-wait';\nimport type { SlotComponentProperties, SlotProperties, SlotTarget } from './slot';\n\nfunction boundedCapacity(value: number, label: string): number {\n if (!Number.isSafeInteger(value) || value < 1 || value > 10_000) {\n throw new RangeError(`${label} must be an integer from 1 to 10000.`);\n }\n\n return value;\n}\n\nfunction validateHost(host: unknown): void {\n if (host === null || typeof host !== 'object' || !('mount' in host) || typeof host.mount !== 'function') {\n throw new TypeError('Scenario requires a host.mount(Component) adapter.');\n }\n}\n\n/** A callable structural Readable still names a source, so its protocol wins over the callback form. */\nfunction isScenarioWaitSource(value: unknown): value is Readable<unknown> | ResourceView<unknown> {\n if (isResourceView(value)) return true;\n if ((typeof value !== 'object' || value === null) && typeof value !== 'function') return false;\n\n return 'getSnapshot' in value && typeof value.getSnapshot === 'function';\n}\n\n/**\n * What the scenario hands to `openApplication`: absence is preserved separately from an explicitly invalid value,\n * so the condition-dependent type and the D281 omissions behave exactly as they do for a host.\n */\nfunction applicationOpenOptions<const Features extends ScenarioFeatures>(\n options: ScenarioOptions<\n Features,\n ScenarioHostMount,\n readonly ApplicationConditionBinding[],\n readonly ApplicationImportBinding[],\n ErrorReporter | 'collect'\n >,\n reporter: ErrorReporter,\n): OpenApplicationOptions<Features> {\n return {\n ...(options.cleanupFailure === undefined ? {} : { cleanupFailure: options.cleanupFailure }),\n ...(hasOwn(options, 'conditions') ? { conditions: options.conditions } : {}),\n /*\n * D366: a scenario opens a real application, so the window of a lease is the host's word here too. D407: the\n * word is the key, as it already is for `conditions` and `imports` beside it — a `grace` written as `undefined`\n * travels to `openApplication` and is refused there, instead of being dropped here into the `0` of a host that\n * wrote no window at all.\n */\n ...(hasOwn(options, 'grace') ? { grace: options.grace! } : {}),\n ...(hasOwn(options, 'imports') ? { imports: options.imports } : {}),\n reporter,\n } as OpenApplicationOptions<Features>;\n}\n\nconst keepNothing = (): void => undefined;\n\n/** D407: a written `act` is the renderer's function; one written as anything else is refused, not dropped. */\nfunction readAct(options: { readonly act?: ActFunction }): ActFunction | undefined {\n if (hasOwn(options, 'act') && typeof options.act !== 'function') {\n throw new TypeError(\"Scenario act must be the renderer's act function; leave it out to render without one.\");\n }\n\n return options.act;\n}\n\n/** A collecting reporter retains the same array until after the scenario closes. */\nfunction scenarioReporter(choice: ErrorReporter | 'collect'): {\n readonly reporter: ErrorReporter;\n readonly reported?: unknown[];\n} {\n if (choice !== 'collect') return { reporter: choice };\n const reported: unknown[] = [];\n return { reported, reporter: error => void reported.push(error) };\n}\n\n/* D206: one real application, its existing inspection session and renderer-owned Slot ingress. */\n/**\n * One real application, its existing inspection session and renderer-owned Slot ingress.\n */\nfunction createScenario<\n const Features extends ScenarioFeatures,\n Mounted extends ScenarioHostMount,\n const Bindings extends readonly ApplicationConditionBinding[] = readonly [],\n const Imports extends readonly ApplicationImportBinding[] = readonly [],\n const Choice extends ErrorReporter | 'collect' = ErrorReporter,\n>(\n application: Application<Features>,\n options: ScenarioOptions<NoInfer<Features>, Mounted, Bindings, Imports, Choice>,\n): Scenario<Mounted, Choice> {\n const timeoutMs = options.timeoutMs;\n if (timeoutMs !== undefined) positiveDuration(timeoutMs, 'Scenario timeoutMs');\n const act = readAct(options);\n // D541: a step on the tree runs inside the renderer's act when the scenario was given one.\n const acted = <Value>(run: () => Value): Value => (act === undefined ? run() : actNow(act, run));\n // D541: installed while a tree of this scenario is mounted, so the deliveries it subscribes run inside `act`.\n const installMountAct = (): (() => void) => (act === undefined ? keepNothing : installAct(act));\n const historyCapacity = boundedCapacity(options.historyCapacity ?? 64, 'Scenario historyCapacity');\n const activityCapacity = boundedCapacity(options.activityCapacity ?? 256, 'Scenario activityCapacity');\n let host: ScenarioHost<Mounted> | undefined = options.host;\n\n validateHost(host);\n\n const { reported, reporter } = scenarioReporter(options.reporter);\n let execution: ApplicationExecution | undefined = openApplication(\n application,\n applicationOpenOptions(options, reporter),\n );\n let session: RuntimeInspectionSession;\n try {\n session = createInspectionSession(execution, { activityCapacity, ringCapacity: historyCapacity });\n } catch (error) {\n void execution.ready.catch(() => undefined);\n void execution.close().catch(() => undefined);\n throw error;\n }\n\n let phase: 'closed' | 'closing' | 'open' = 'open';\n let successfullyClosed = false;\n let capturing = false;\n const records: RuntimeGraphSnapshot[] = [];\n const mounts = new Set<ScenarioMountLease<Mounted>>();\n const mountFailures: unknown[] = [];\n const getSnapshot = (): RuntimeGraphSnapshot => session.getSnapshot();\n const history = (): readonly RuntimeGraphSnapshot[] => Object.freeze([...records]);\n const waiters = new ScenarioWaiters({\n getSnapshot,\n history,\n get timeoutMs() {\n return timeoutMs ?? testingTimeoutMs();\n },\n });\n const capture = (): void => {\n if (capturing) return;\n\n capturing = true;\n try {\n const snapshot = getSnapshot();\n const previous = records[records.length - 1];\n\n if (previous?.stateRevision !== snapshot.stateRevision || previous.activity !== snapshot.activity) {\n records.push(snapshot);\n\n if (records.length > historyCapacity) records.shift();\n }\n } finally {\n capturing = false;\n }\n waiters.notify();\n };\n const release = session.subscribe(capture);\n capture();\n const ready = waiters.deadline(execution.ready, 'application ready');\n // A test may deliberately inspect loading without awaiting ready; rejection remains observable to that caller.\n void ready.catch(() => undefined);\n\n let physicalClose: Promise<void> | undefined;\n let closeAttempt: Promise<void> | undefined;\n const startClose = (): Promise<void> => {\n if (physicalClose !== undefined) return physicalClose;\n\n let resolve!: () => void;\n let reject!: (error: unknown) => void;\n physicalClose = new Promise<void>((accept, refuse) => {\n resolve = accept;\n reject = refuse;\n });\n phase = 'closing';\n waiters.cancel();\n const drains: Promise<void>[] = [];\n // Fence before any foreign unmount callback can reenter UI ingress; join all physical drains afterwards.\n try {\n drains.push(execution!.close());\n } catch (error) {\n drains.push(Promise.reject(error));\n }\n drains.push(...[...mounts].map(mount => mount.close()));\n void Promise.allSettled(drains).then(results => {\n const failures = [\n ...new Set([\n ...mountFailures,\n ...results.flatMap(result => (result.status === 'rejected' ? [result.reason as unknown] : [])),\n ]),\n ];\n mountFailures.length = 0;\n phase = 'closed';\n try {\n capture();\n } catch (error) {\n failures.push(error);\n } finally {\n release();\n session.close();\n mounts.clear();\n execution = undefined;\n host = undefined;\n }\n successfullyClosed = failures.length === 0;\n\n if (failures.length === 0) resolve();\n else reject(createAggregateError(failures, 'Scenario cleanup failed.'));\n });\n\n return physicalClose;\n };\n\n const attemptClose = (): Promise<void> => {\n const drain = startClose();\n\n // A nested close during unmount may have installed the same attempt already.\n if (closeAttempt !== undefined) return closeAttempt;\n\n closeAttempt = waiters.deadline(drain, 'scenario close');\n void closeAttempt.catch(() => {\n // A deadline cannot cancel physical work. A later close can await that same drain with a new deadline.\n if (phase === 'closing') closeAttempt = undefined;\n });\n\n return closeAttempt;\n };\n // D541: the fence, the waits it cancels, the retirement it publishes to mounted components and their unmount share\n // one synchronous act scope; the drain that follows has no tree left to render.\n const close = (): Promise<void> => closeAttempt ?? acted(attemptClose);\n\n const mount: Scenario<Mounted>['mount'] = <Props extends SlotProperties>(\n target: SlotTarget<Props>,\n fixture: { readonly props?: SlotComponentProperties<Props> } = {},\n ): ScenarioMount<Props, Mounted> => {\n if (phase !== 'open') throw new Error('Scenario is closing.');\n\n const slot = createSlotHarness(target, fixture);\n const uninstallAct = installMountAct();\n const lease = new ScenarioMountLease<Mounted>((failed, error) => {\n mounts.delete(lease);\n slot.close();\n uninstallAct();\n\n if (failed) mountFailures.push(error);\n }, act);\n mounts.add(lease);\n let mounted: Mounted;\n try {\n mounted = acted(() => host!.mount(slot.Slot));\n\n if (mounted === null || typeof mounted !== 'object' || typeof mounted.unmount !== 'function') {\n throw new TypeError('Scenario host.mount must return an unmount() handle.');\n }\n\n lease.provide(mounted);\n } catch (error) {\n // D541: a host that failed mounts no tree, so its `act` is removed before the failure reaches the test.\n uninstallAct();\n lease.provide(undefined);\n void lease.close().catch(() => undefined);\n throw error;\n }\n\n return Object.freeze({\n host: mounted,\n unmount: lease.close,\n updateProps: (props: SlotComponentProperties<Props>): void => {\n if (phase !== 'open' || lease.closed) throw new Error('Scenario mount is closed.');\n\n acted(() => slot.updateProps(props));\n waiters.notify();\n },\n });\n };\n\n function scenarioWaitFor<Value>(\n read: ScenarioReadWithoutAccept<Value>,\n options?: ScenarioWaitOptions,\n ): Promise<Exclude<Value, false | null | undefined>>;\n function scenarioWaitFor<Value, Narrowed extends Value>(\n source: Readable<Value> | ResourceView<Value>,\n accept: (value: Value) => value is Narrowed,\n options?: ScenarioWaitOptions,\n ): Promise<Narrowed>;\n function scenarioWaitFor<Value>(\n source: Readable<Value> | ResourceView<Value>,\n accept: (value: Value) => boolean,\n options?: ScenarioWaitOptions,\n ): Promise<Value>;\n function scenarioWaitFor<Value, Narrowed extends Value>(\n read: (snapshot: RuntimeGraphSnapshot) => Value,\n accept: (value: Value) => value is Narrowed,\n options?: ScenarioWaitOptions,\n ): Promise<Narrowed>;\n function scenarioWaitFor<Value>(\n read: (snapshot: RuntimeGraphSnapshot) => Value,\n accept: (value: Value) => boolean,\n options?: ScenarioWaitOptions,\n ): Promise<Value>;\n function scenarioWaitFor(\n read: ((snapshot: RuntimeGraphSnapshot) => unknown) | Readable<unknown> | ResourceView<unknown>,\n second?: ScenarioWaitOptions | ((value: unknown) => boolean),\n third?: ScenarioWaitOptions,\n ): Promise<unknown> {\n if (phase !== 'open') return Promise.reject(new Error('Scenario is closing.'));\n const accept = typeof second === 'function' ? second : undefined;\n const waitOptions = (accept === undefined ? second : third) ?? {};\n const request = isResourceView(read)\n ? { kind: 'source' as const, read: () => read.observe().getSnapshot() }\n : isScenarioWaitSource(read)\n ? { kind: 'source' as const, read: () => read.getSnapshot() }\n : { kind: 'graph' as const, read };\n return waiters.waitFor(request, accept, waitOptions as ScenarioWaitOptions);\n }\n\n const scenario = {\n close,\n getSnapshot,\n history,\n mount,\n notify: (): void => {\n if (phase === 'open') waiters.notify();\n },\n ownership: () => scenarioOwnership(getSnapshot(), successfullyClosed),\n ready,\n waitFor: scenarioWaitFor,\n };\n if (reported !== undefined) {\n Object.defineProperty(scenario, 'reported', { enumerable: true, get: () => Object.freeze([...reported]) });\n }\n return Object.freeze(scenario) as unknown as Scenario<Mounted, Choice>;\n}\n\nexport { createScenario };\n"],"names":["instanceFacts","instance","waiting","callFact","call","blockers","activityFacts","activity","facts","feature","resource","explainSnapshot","snapshot","condition","ScenarioTimeoutError","label","timeoutMs","history","ownershipComplete","successfullyClosed","ownershipReasons","complete","reasons","ownershipCounts","scenarioOwnership","ScenarioMountLease","released","act","resolve","reject","handle","failed","error","unmount","actNow","testingContributionId","declarationId","createSlotHarness","target","fixture","fixtures","current","listeners","props","listener","supplied","reported","fixtureAuthority","published","useReadable","slotProps","entry","contributionAuthority","contributionId","contribution","authority","createElement","ContributionMount","next","renderSlot","harness","positiveDuration","value","ScenarioWaiters","source","result","timer","request","accept","options","pollIntervalMs","readValue","synchronous","half","done","dispose","finish","check","cancel","deadline","poll","boundedCapacity","validateHost","host","isScenarioWaitSource","isResourceView","applicationOpenOptions","reporter","hasOwn","keepNothing","readAct","scenarioReporter","choice","createScenario","application","acted","run","installMountAct","installAct","historyCapacity","activityCapacity","execution","openApplication","session","createInspectionSession","phase","capturing","records","mounts","mountFailures","getSnapshot","waiters","testingTimeoutMs","capture","previous","release","ready","physicalClose","closeAttempt","startClose","refuse","drains","mount","results","failures","createAggregateError","attemptClose","drain","close","slot","uninstallAct","lease","mounted","scenarioWaitFor","read","second","third","waitOptions","scenario"],"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.16.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=20.19.0"
|
|
6
6
|
},
|
|
@@ -49,16 +49,16 @@
|
|
|
49
49
|
}
|
|
50
50
|
],
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@opetope/core": "0.
|
|
53
|
-
"@opetope/runtime": "0.
|
|
52
|
+
"@opetope/core": "0.16.0",
|
|
53
|
+
"@opetope/runtime": "0.16.0",
|
|
54
54
|
"@testing-library/react": "16.3.3",
|
|
55
55
|
"@types/react": "19.2.18",
|
|
56
56
|
"react": "19.2.8",
|
|
57
57
|
"react-dom": "19.2.8"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@opetope/core": "0.
|
|
61
|
-
"@opetope/runtime": "0.
|
|
60
|
+
"@opetope/core": "0.16.0",
|
|
61
|
+
"@opetope/runtime": "0.16.0",
|
|
62
62
|
"react": ">=19.0.0 <20"
|
|
63
63
|
},
|
|
64
64
|
"sideEffects": false,
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{jsx as m}from"react/jsx-runtime";import{useContext as V,createContext as D,useCallback as S,useRef as O,useMemo as p,useSyncExternalStore as k,useEffect as N,useInsertionEffect as A,useLayoutEffect as w,memo as W,useState as K}from"react";import{reportDetachedError as C,compatibleAbortReason as _,isCallTarget as G,isModel as H,isReadable as j,isResourceView as F,createLifetimeController as J,createCallController as Q,getContributionOwner as U,createState as X,createAggregateError as Y}from"@opetope/core/internal";import{isResourceValue as Z,reportRuntimeFailure as ee,requireContributionModelPlans as te,openContributionModels as ne}from"@opetope/runtime/internal";import{C as u,u as re,b as ie}from"./contribution-isolation-Bzfbt4iM.js";import{CommandError as oe}from"@opetope/core";const x=D(void 0);function se(){const t=V(x);if(t===void 0)throw new u("missing","Opetope hook was called outside a contribution mount.");return t}function y(t){return Z(t)}function ae(t,e){return new Promise((n,r)=>{const i=()=>{r(new oe("cancelled","Resource operation wait was cancelled.",_(e)))};if(e.aborted){i();return}e.addEventListener("abort",i,{once:!0}),t.then(o=>{e.removeEventListener("abort",i),n(o)},o=>{e.removeEventListener("abort",i),r(o)})})}function ce(t,e){var r;const n=(r=e==null?void 0:e.onSuccess)==null?void 0:r.call(e,t);return n!==void 0&&Promise.resolve(n).catch(C),t}function v(t){return{run:(e,n)=>{let r;try{r=Promise.resolve(t())}catch(o){return Promise.reject(o)}const i=n==null?void 0:n.signal;return(i===void 0?r:ae(r,i)).then(o=>ce(o,n))}}}const de=Object.freeze({kind:"skipped",reason:"resource-not-ready"});function ue(t){const e=t.pagination;if(!(typeof e!="object"||e===null))return e}function E(t){return{loadNext:v(()=>{const e=t.pagination;return e===void 0?Promise.resolve(de):e.loadNext()}),refresh:v(()=>t.refresh()),reset:v(()=>t.reset()),retry:v(()=>t.retry())}}function le(t,e){const n=e.get(t);if(n!==void 0)return n;const r=E(t);return e.set(t,r),r}const fe=t=>t;function z(t,e,n){const r=e,i=(n==null?void 0:n.equals)??Object.is,o=S(d=>t.subscribe(d),[t]),c=O(void 0);let s=c.current;s===void 0&&(s={hasValue:!1,value:void 0},c.current=s);const a=p(()=>{let d=!1,h,f;return()=>{const b=t.getSnapshot();if(d&&Object.is(h,b))return f;const g=r(b);if(!d){let R=g;return s.hasValue&&i(s.value,g)&&(R=s.value),d=!0,h=b,f=R,f}return i(f,g)?(h=b,f):(h=b,f=g,f)}},[s,i,t,r]),l=k(o,a,a);return N(()=>{s.hasValue=!0,s.value=l},[s,l]),l}function I(t){return z(t,fe)}const M=new WeakMap;function $(t){if(arguments.length>1)throw new u("binding-invalid","Command follows the target it binds; binding options are forbidden.");if(!G(t))throw new u("binding-invalid","Command target is not authentic.");return M.set(t,{target:t}),t}function he(t){const e=M.get(t);if(e===void 0)throw new u("binding-invalid","Command binding is not authentic.");return e}function L(t){return typeof t=="object"&&t!==null&&M.has(t)}const me=Symbol("opetope.model-binding"),be=Symbol("opetope.model-binding-identity"),pe=Object.freeze({}),q=new WeakMap;function ge(t,e,n){if(typeof n!="string")throw new u("binding-invalid",`Model ${t.id} accepts only string fields.`);const r=Object.getOwnPropertyDescriptor(e,n);if((r==null?void 0:r.enumerable)!==!0||!("value"in r))throw new u("binding-invalid",`Model ${t.id}.${n} requires an enumerable data binding.`);return r.value}function we(t){return j(t)||y(t)||F(t)||typeof t=="function"}function Ce(t,e){const n=[],r=Reflect.ownKeys(e);if(r.length===0)throw new u("binding-invalid",`Model ${t.id} requires at least one field.`);for(const i of r){const o=ge(t,e,i);if(!we(o)){if(!L(o))throw new u("binding-invalid",`Model ${t.id}.${String(i)} requires a Readable, a Resource, a ResourceView or a bound command.`);n.push(o)}}return Object.freeze(n)}function B(t,e){if(!H(t))throw new u("binding-invalid","Model declaration is not authentic.");if(typeof e!="object"||e===null)throw new u("binding-invalid",`Model ${t.id} requires a record binding.`);const n=Ce(t,e),r=Object.freeze({[me]:pe,[be]:!0});return q.set(r,{commands:n,declaration:t,model:e}),r}function ve(t){const e=q.get(t);if(e===void 0)throw new u("binding-invalid","Model binding is not authentic.");return e}let ye=0;function Me(t){const e=new Map,n=[],r=new Set;for(const i of t){const o=ve(i);if(e.has(o.declaration))throw new u("duplicate",`Model ${o.declaration.id} is bound twice in one mount.`);e.set(o.declaration,o.model);for(const c of o.commands)r.has(c)||(r.add(c),n.push(c))}return{commands:Object.freeze(n),frame:{commandRecords:new Map,models:e}}}class Re{frame;authority;boundCommands;closeTicket=0;isActive;lifetime;onClose;released=!1;rendererAttached=!1;renderListeners=new Set;state="detached";constructor(e,n){const r=++ye;this.lifetime=J({id:`contribution.${String(r)}`}),this.isActive=n==null?void 0:n.isActive,this.onClose=n==null?void 0:n.onClose;const{commands:i,frame:o}=Me(e);this.frame=o,this.boundCommands=i,this.buildCommandRecords(r)}attach(){if(this.state==="closing")return this.closeTicket+=1,this.state="active",this.rendererAttached=!0,!0;if(this.state==="closed")return!1;if(this.state==="active")throw new u("duplicate","One contribution mount cannot mount twice.");const e=this.createAuthority(this.lifetime.open());try{for(const n of this.frame.commandRecords.values())n.controller.activate()}catch(n){throw this.authority=e,this.state="active",this.close(),n}return this.authority=e,this.rendererAttached=!0,this.state="active",!0}close(){if(this.state==="closed")return;this.state="closed",this.closeTicket+=1,this.lifetime.close(),this.authority=void 0;for(const n of this.frame.commandRecords.values())n.controller.close();const e=this.onClose;this.onClose=void 0,e==null||e(),this.publishRenderable(),this.rendererAttached||this.releaseFrame()}detach(){if(!this.rendererAttached)return;if(this.rendererAttached=!1,this.state==="closed"){this.releaseFrame();return}if(this.state!=="active")return;this.state="closing";const e=++this.closeTicket;queueMicrotask(()=>{this.state==="closing"&&e===this.closeTicket&&this.close()})}diagnostics(){const e=[...this.frame.commandRecords.values()].map(n=>n.controller.diagnostics());return Object.freeze({active:this.state==="active",calls:Object.freeze(e),commandRecords:this.frame.commandRecords.size,models:this.frame.models.size})}getRenderableSnapshot=()=>this.state!=="closed"&&(this.isActive===void 0||this.isActive());releaseClosedFrame(){this.state==="closed"&&this.releaseFrame()}subscribeRenderable=e=>{if(this.state==="closed")return()=>{};const n={listener:e};this.renderListeners.add(n);let r=!0;return()=>{r&&(r=!1,this.renderListeners.delete(n))}};buildCommandRecords(e){let n=0;for(const r of this.boundCommands){he(r);const i=Q(r,{captureAuthority:this.captureAuthority,id:`contributionCommand.${String(e)}.${String(++n)}`,scheduling:{policy:"parallel"}});this.frame.commandRecords.set(r,{controller:i,invoker:Object.freeze({run:i.run})})}}captureAuthority=()=>{const e=this.authority;if(this.state!=="active"||e===void 0)throw new u("inactive","Contribution mount is not active.");return e.assertCurrent(),e};createAuthority(e){return Object.freeze({assertCurrent:()=>{if(this.state!=="active")throw new u("inactive","Contribution mount is not active.");e.assertCurrent()},isCurrent:()=>this.state==="active"&&e.isCurrent()})}publishRenderable(){for(const{listener:e}of[...this.renderListeners])try{e()}catch(n){C(n)}}releaseFrame(){this.released||(this.released=!0,this.frame.commandRecords.clear(),this.frame.models.clear(),this.boundCommands=[],this.renderListeners.clear())}}function Se({children:t,mount:e}){const n=k(e.subscribeRenderable,e.getRenderableSnapshot,e.getRenderableSnapshot);return A(()=>{if(e.attach())return()=>e.detach()},[e]),w(()=>{n||e.releaseClosedFrame()},[e,n]),n?m(x,{value:e.frame,children:t}):null}function P(t){const e=t.bundle;t.bundle=void 0,e==null||e.frame.close()}function Oe(t,e){if(typeof e!="object"||e===null)return B(t,e);const n=i=>j(i)||y(i)||F(i)||typeof i=="function"||L(i),r=Object.entries(e).map(([i,o])=>[i,n(o)?o:$(o)]);return B(t,Object.fromEntries(r))}function ke(t){return U(t)}const Ae={models:[]};function T(t,e){try{t()}catch(n){throw Y([e,n],"Contribution mount setup and cleanup failed.",{cause:e})}throw e}function je(t,e,n,r){const i=X(e),{models:o,reporter:c}=r??Ae;try{const s=te(t.models),a=s.length===0?void 0:ne(s,i,c);return{bundle:a,models:[...o,...(a==null?void 0:a.models)??[],...n],props:i}}catch(s){return T(i.close,s)}}function Fe(t,e,n,r){const{bundle:i,models:o,props:c}=je(t,e,n,r);let s=!1;const a=()=>{if(!s){s=!0;try{i==null||i.close().catch(C)}finally{c.close()}}};try{return{frame:new Re(o.map(([d,h])=>Oe(d,h)),{isActive:()=>!s,onClose:a}),isOpen:()=>!s,props:c}}catch(l){return T(a,l)}}function xe(t,e){return m(t,{...e})}function Ee({bundle:t,contribution:e}){const n=I(t.props),r=p(()=>e.props===void 0?n:e.props(n),[n,e]);return m(Se,{mount:t.frame,children:xe(e.Component,r)})}function ze({authority:t,contribution:e,fixtures:n,slotProps:r}){const i=p(()=>({authority:t,bundle:void 0,contribution:e,fixtures:n,retired:!1}),[t,e,n]),[o,c]=K(void 0),s=(o==null?void 0:o.owner)===i?o.bundle:void 0,a=O(r);return w(()=>{a.current=r}),A(()=>()=>{i.retired=!0,queueMicrotask(()=>{try{P(i)}catch(l){C(l)}})},[i]),w(()=>{const l=i.bundle??(i.bundle=Fe(i.contribution,a.current,i.fixtures??[],i.authority));return c(d=>(d==null?void 0:d.owner)===i?d:{bundle:l,owner:i}),()=>{i.retired&&P(i)}},[i]),w(()=>{(s==null?void 0:s.isOpen())===!0&&s.props.set(r)},[s,r]),s===void 0?null:m(Ee,{bundle:s,contribution:e})}function Ie(t){const{authority:e,contribution:n,contributionId:r,fixtures:i,targetId:o}=t,c=re(),s=p(()=>({authority:e,contribution:n,fixtures:i}),[e,n,i]),a=e==null?void 0:e.feature,l=p(()=>({contribution:r,feature:a,target:o}),[r,a,o]),d=e==null?void 0:e.reporter,h=S(f=>ee(f,d),[d]);return m(ie,{content:c,identity:s,report:h,source:l,children:m(ze,{...t})})}const $e=W(Ie);export{$e as M,I as a,ke as b,E as c,z as d,$ as e,y as i,ue as p,le as r,se as u};
|
|
2
|
-
//# sourceMappingURL=contribution-frame-Bh104T5Z.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contribution-frame-Bh104T5Z.js","sources":["../src/mount-context.tsx","../src/resource-command.ts","../src/readable-hooks.ts","../src/command.ts","../src/model-binding.ts","../src/mount-frame.ts","../src/mount-provider.tsx","../src/contribution-frame.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport { ContributionError } from './errors';\nimport type { Frame } from './mount-frame';\n\nconst FrameContext = createContext<Frame | undefined>(undefined);\n\nfunction useFrame(): Frame {\n const frame = useContext(FrameContext);\n\n if (frame === undefined) {\n throw new ContributionError('missing', 'Opetope hook was called outside a contribution mount.');\n }\n\n return frame;\n}\n\nexport { FrameContext, useFrame };\n","/**\n * D359: the verbs of a Resource, dressed as the commands a button already knows, and the recognition that answers\n * «is this selected field a Resource». A consumer keeps a status — `inFlight` until the operation settles, the\n * settled `outcome` — while the Resource stays owned by the model that declared it: cancelling this wait cancels the\n * wait and not the load.\n */\n\nimport { CommandError } from '@opetope/core';\nimport type {\n PaginationOutcome,\n PaginationState,\n Resource,\n ResourceOperationOutcome,\n ResourcePagination,\n ResourceState,\n} from '@opetope/core';\nimport { compatibleAbortReason, reportDetachedError } from '@opetope/core/internal';\nimport type { CallRunOptions, ResourceKey } from '@opetope/core/internal';\nimport { isResourceValue } from '@opetope/runtime/internal';\n\nimport type { CommandHook } from './command-hook';\nimport type { CommandInvoker } from './command-hook-controller';\n\n/**\n * D439: the widest Resource, and the name says so. `Resource<never, ResourceKey>` said the opposite in both\n * arguments — `never` is the narrowest `Data` a reader can be handed and a named `Key` *requires* `state.key`, so\n * hardly any member of the family fitted it. Nothing was refused, because every value reaches this name through a\n * cast, which is exactly why the name could drift. `ResourceKeyField<never>` requires no field, so\n * `Resource<unknown, never, 'consumers' | 'owner'>` is the one form every Resource satisfies — keyed or not, paginated or not.\n */\ntype AnyResource = Resource<unknown, never, 'consumers' | 'owner'>;\n\n/**\n * D349, D359: a Resource is a structural contract a host may implement with an ordinary object, so the question the\n * type of a selected field asked is answered by the runtime that owns it — the registry of the materializations it\n * built, and the structural contract for everything else. Asking it here a second time would let the two answers\n * drift, and a host adapter typed as a hook reaches the render where `state` is `undefined` and `refresh.run()`\n * throws.\n */\nfunction isResource(value: unknown): boolean {\n return isResourceValue(value);\n}\n\n/** D356: the nested capability, with `loadNext` as a command and the projected pagination state beside it. */\ntype ResourcePaginationHook<Cursor extends ResourceKey> = Readonly<{\n loadNext: CommandHook<void, PaginationOutcome<Cursor>>;\n state: PaginationState<Cursor>;\n}>;\n\n/**\n * D359: what `useResource` answers, and what a field of a `useModel` selection whose value is a Resource answers.\n * The verbs never reject (a Resource answers an outcome), so the ordinary path of `outcome` is\n * `{ kind: 'ok', value }`; `failed` stays in the type because the controller turns a synchronous throw of an\n * invoker into it, and the wrapper below carries its own test that it never throws synchronously.\n */\ntype ResourceHook<Data, Key extends ResourceKey = never> = Readonly<{\n /** Present when the declaration carried `pagination`; `undefined` for every other Resource. */\n pagination: ResourcePaginationHook<ResourceKey> | undefined;\n refresh: CommandHook<void, ResourceOperationOutcome>;\n reset: CommandHook<void, ResourceOperationOutcome>;\n retry: CommandHook<void, ResourceOperationOutcome>;\n state: ResourceState<Data, Key>;\n}>;\n\ntype PaginatedResourceHook<Data, Key extends ResourceKey, Cursor extends ResourceKey> = Omit<\n ResourceHook<Data, Key>,\n 'pagination'\n> &\n Readonly<{ pagination: ResourcePaginationHook<Cursor> }>;\n\ntype ResourceInvokers = Readonly<{\n loadNext: CommandInvoker;\n refresh: CommandInvoker;\n reset: CommandInvoker;\n retry: CommandInvoker;\n}>;\n\n/** The consumer's own cancellation: it ends this wait, and the work the model owns keeps running. */\nfunction awaitCancellable(operation: Promise<unknown>, signal: AbortSignal): Promise<unknown> {\n return new Promise<unknown>((resolve, reject) => {\n const cancel = (): void => {\n reject(new CommandError('cancelled', 'Resource operation wait was cancelled.', compatibleAbortReason(signal)));\n };\n\n if (signal.aborted) {\n cancel();\n\n return;\n }\n\n signal.addEventListener('abort', cancel, { once: true });\n operation.then(\n value => {\n signal.removeEventListener('abort', cancel);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener('abort', cancel);\n reject(error);\n },\n );\n });\n}\n\nfunction notifySuccess(value: unknown, options: CallRunOptions<unknown> | undefined): unknown {\n const notification = options?.onSuccess?.(value);\n\n // The failure of a consumer's own callback is detached from the operation it watched, as it is for a command.\n if (notification !== undefined) void Promise.resolve(notification).catch(reportDetachedError);\n\n return value;\n}\n\n/**\n * The invariant of this wrapper: it never throws synchronously, so the `failed` outcome a consumer can see is the one\n * the verb itself produced and never one this layer invented in the middle of a render commit.\n */\nfunction operationInvoker(start: () => Promise<unknown>): CommandInvoker {\n return {\n run: (_input: never, options?: CallRunOptions<unknown>): Promise<unknown> => {\n let operation: Promise<unknown>;\n\n try {\n operation = Promise.resolve(start());\n } catch (error) {\n return Promise.reject(error);\n }\n\n const signal = options?.signal;\n\n return (signal === undefined ? operation : awaitCancellable(operation, signal)).then(value =>\n notifySuccess(value, options),\n );\n },\n };\n}\n\n/** A Resource without the capability still answers a `loadNext` invoker, so the hook count never moves. */\nconst unavailablePage: PaginationOutcome<ResourceKey> = Object.freeze({\n kind: 'skipped',\n reason: 'resource-not-ready',\n});\n\nfunction paginationOf(resource: AnyResource): ResourcePagination<ResourceKey, 'consumers' | 'owner'> | undefined {\n const capability = (resource as { readonly pagination?: unknown }).pagination;\n\n if (typeof capability !== 'object' || capability === null) return undefined;\n\n return capability as ResourcePagination<ResourceKey, 'consumers' | 'owner'>;\n}\n\n/**\n * One set per Resource identity. `selectEntry` and `useCommandSlot` both pick their controller by the identity of the\n * invoker, so a set rebuilt on every render would reset `inFlight`, drop `outcome` and change `run` — which is why it\n * is memoised against the Resource itself and never assembled during a render.\n */\nfunction createResourceInvokers(resource: AnyResource): ResourceInvokers {\n // D349: a Resource is a structural contract, so every verb is called through it and never as a detached function.\n return {\n loadNext: operationInvoker(() => {\n const capability = (resource as { readonly pagination?: { loadNext(): Promise<unknown> } }).pagination;\n\n return capability === undefined ? Promise.resolve(unavailablePage) : capability.loadNext();\n }),\n refresh: operationInvoker(() => resource.refresh()),\n reset: operationInvoker(() => resource.reset()),\n retry: operationInvoker(() => resource.retry()),\n };\n}\n\nfunction resourceInvokers(resource: AnyResource, cache: WeakMap<object, ResourceInvokers>): ResourceInvokers {\n const existing = cache.get(resource);\n\n if (existing !== undefined) return existing;\n\n const invokers = createResourceInvokers(resource);\n cache.set(resource, invokers);\n\n return invokers;\n}\n\n/**\n * The one module of this package that talks to the runtime about a materialization, so the rest of React reads the\n * recognition and the key type from here instead of routing to `@opetope/runtime/internal` of its own.\n */\nexport { createResourceInvokers, isResource, paginationOf, resourceInvokers };\nexport type { AnyResource, PaginatedResourceHook, ResourceHook, ResourceInvokers, ResourceKey, ResourcePaginationHook };\n","import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from 'react';\n\nimport type { Readable } from '@opetope/core';\nimport type { EqualityOption } from '@opetope/core/internal';\n\nconst identity = <Value>(value: Value): Value => value;\n\n/**\n * D364: what this mount answered last, and nothing about closes. A source whose owner retired stops instead of\n * refusing — it keeps answering its last value — so a render that races a retirement shows its last frame and\n * unmounts (G13) without the reader having to remember anything for it.\n */\ninterface SelectionInstance<Selected> {\n hasValue: boolean;\n value: Selected | undefined;\n}\n\n/**\n * D279: the source and the selection are positional; `equals` is the one modifier, spelled as in Core — including\n * D348's rule for where the comparator is read, so a named non-generic one compiles here as it does in `derive`.\n */\nexport function useSelector<Value, Selected>(\n readable: Readable<Value>,\n select: (value: NoInfer<Value>) => Selected,\n options?: { readonly equals?: EqualityOption<NoInfer<Selected>> },\n): Selected {\n const selector = select;\n const isEqual = options?.equals ?? Object.is;\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const instanceRef = useRef<SelectionInstance<Selected> | undefined>(undefined);\n let instance = instanceRef.current;\n\n if (instance === undefined) {\n instance = { hasValue: false, value: undefined };\n instanceRef.current = instance;\n }\n\n const getSelectedSnapshot = useMemo(() => {\n let initialized = false;\n let sourceSnapshot: Value;\n let selectedSnapshot: Selected;\n\n return (): Selected => {\n const nextSource = readable.getSnapshot();\n\n if (initialized && Object.is(sourceSnapshot, nextSource)) return selectedSnapshot;\n\n const nextSelected = selector(nextSource);\n\n if (!initialized) {\n let nextSelectedSnapshot = nextSelected;\n\n if (instance.hasValue && isEqual(instance.value, nextSelected)) {\n nextSelectedSnapshot = instance.value as Selected;\n }\n\n initialized = true;\n sourceSnapshot = nextSource;\n selectedSnapshot = nextSelectedSnapshot;\n\n return selectedSnapshot;\n }\n\n if (isEqual(selectedSnapshot, nextSelected)) {\n sourceSnapshot = nextSource;\n\n return selectedSnapshot;\n }\n\n sourceSnapshot = nextSource;\n selectedSnapshot = nextSelected;\n\n return selectedSnapshot;\n };\n }, [instance, isEqual, readable, selector]);\n\n const selected = useSyncExternalStore(subscribe, getSelectedSnapshot, getSelectedSnapshot);\n\n useEffect(() => {\n instance.hasValue = true;\n instance.value = selected;\n }, [instance, selected]);\n\n return selected;\n}\n\nexport function useReadable<Value>(readable: Readable<Value>): Value {\n return useSelector(readable, identity);\n}\n","import type { Command } from '@opetope/core';\nimport { isCallTarget } from '@opetope/core/internal';\n\nimport { ContributionError } from './errors';\n\n/**\n * A bound command is the authentic `Command` the model field declares, so the common path adds no wrapper. Observable\n * call state belongs to the model as a `Readable` field (D71), so a binding carries no mode.\n */\ntype CommandBindingIdentity = Command<never, unknown>;\ntype CommandBinding<Input, Output> = Command<Input, Output>;\n\ntype CommandOutcome<Output> =\n | { readonly error: unknown; readonly kind: 'failed' }\n | { readonly reason: unknown; readonly kind: 'cancelled' }\n | { readonly kind: 'ok'; readonly value: Output };\n\ntype AnyCommandBinding = CommandBinding<never, unknown>;\n\ntype CommandBindingDefinition<Input, Output> = {\n readonly target: Command<Input, Output>;\n};\n\nconst bindingDefinitions = new WeakMap<CommandBindingIdentity, CommandBindingDefinition<never, unknown>>();\n\nfunction bindCommand<Input, Output>(target: Command<Input, Output>): CommandBinding<Input, Output> {\n if (arguments.length > 1) {\n throw new ContributionError(\n 'binding-invalid',\n 'Command follows the target it binds; binding options are forbidden.',\n );\n }\n\n if (!isCallTarget(target)) throw new ContributionError('binding-invalid', 'Command target is not authentic.');\n\n bindingDefinitions.set(target, { target });\n\n return target;\n}\n\nfunction getCommandBindingDefinition<Input, Output>(\n binding: Command<Input, Output>,\n): CommandBindingDefinition<Input, Output> {\n const definition = bindingDefinitions.get(binding);\n\n if (definition === undefined) throw new ContributionError('binding-invalid', 'Command binding is not authentic.');\n\n return definition as CommandBindingDefinition<Input, Output>;\n}\n\nfunction isCommandBinding(value: unknown): value is AnyCommandBinding {\n return typeof value === 'object' && value !== null && bindingDefinitions.has(value as CommandBindingIdentity);\n}\n\nexport { bindCommand, getCommandBindingDefinition, isCommandBinding };\nexport type { CommandOutcome };\n","import type { Command, ModelOf } from '@opetope/core';\nimport { isModel, isReadable, isResourceView } from '@opetope/core/internal';\nimport type { ExactKeys, ModelIdentity } from '@opetope/core/internal';\n\nimport { isCommandBinding } from './command';\nimport { ContributionError } from './errors';\nimport { isResource } from './resource-command';\n\nconst modelBindingBrand = Symbol('opetope.model-binding');\nconst modelBindingIdentityBrand = Symbol('opetope.model-binding-identity');\nconst modelBindingMarker = Object.freeze({});\n\ntype AnyModel = ModelIdentity;\ntype AnyCommand = Command<never, unknown>;\n\ninterface ModelBindingIdentity {\n readonly [modelBindingIdentityBrand]: true;\n}\n\ninterface ModelBinding<Declaration extends AnyModel> extends ModelBindingIdentity {\n readonly [modelBindingBrand]: (declaration: Declaration) => Declaration;\n}\n\ntype ModelBindingMetadata = {\n readonly commands: readonly AnyCommand[];\n readonly declaration: AnyModel;\n readonly model: object;\n};\n\nconst registry = new WeakMap<ModelBindingIdentity, ModelBindingMetadata>();\n\n/**\n * The declaration carries the field shape in its type; binding also validates fields supplied by host code.\n * ResourceViews travel unchanged, so observing a model never acquires its dependencies.\n */\nfunction modelFieldValue(declaration: AnyModel, model: object, field: PropertyKey): unknown {\n if (typeof field !== 'string') {\n throw new ContributionError('binding-invalid', `Model ${declaration.id} accepts only string fields.`);\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(model, field);\n\n if (descriptor?.enumerable !== true || !('value' in descriptor)) {\n throw new ContributionError(\n 'binding-invalid',\n `Model ${declaration.id}.${field} requires an enumerable data binding.`,\n );\n }\n\n return descriptor.value;\n}\n\nfunction isObservedField(value: unknown): boolean {\n return isReadable(value) || isResource(value) || isResourceView(value) || typeof value === 'function';\n}\n\nfunction snapshotModelFields(declaration: AnyModel, model: object): readonly AnyCommand[] {\n const commands: AnyCommand[] = [];\n const fields = Reflect.ownKeys(model);\n\n if (fields.length === 0)\n throw new ContributionError('binding-invalid', `Model ${declaration.id} requires at least one field.`);\n\n for (const field of fields) {\n const value = modelFieldValue(declaration, model, field);\n\n // D349: a Resource is a field a model publishes, and it is not a `Readable`, so it is recognised by name.\n if (isObservedField(value)) continue;\n\n if (!isCommandBinding(value)) {\n throw new ContributionError(\n 'binding-invalid',\n `Model ${declaration.id}.${String(field)} requires a Readable, a Resource, a ResourceView or a bound command.`,\n );\n }\n\n commands.push(value);\n }\n\n return Object.freeze(commands);\n}\n\nfunction bindModel<Declaration extends AnyModel, const Keys extends PropertyKey = never>(\n declaration: Declaration,\n model: ExactKeys<Keys, ModelOf<Declaration>> & ModelOf<Declaration>,\n): ModelBinding<Declaration> {\n if (!isModel(declaration)) throw new ContributionError('binding-invalid', 'Model declaration is not authentic.');\n\n if (typeof model !== 'object' || model === null) {\n throw new ContributionError('binding-invalid', `Model ${declaration.id} requires a record binding.`);\n }\n\n const commands = snapshotModelFields(declaration, model);\n const binding = Object.freeze({\n [modelBindingBrand]: modelBindingMarker as unknown as (value: Declaration) => Declaration,\n [modelBindingIdentityBrand]: true as const,\n });\n registry.set(binding, { commands, declaration, model });\n\n return binding;\n}\n\nfunction getModelBindingMetadata(binding: ModelBindingIdentity): ModelBindingMetadata {\n const metadata = registry.get(binding);\n\n if (metadata === undefined) throw new ContributionError('binding-invalid', 'Model binding is not authentic.');\n\n return metadata;\n}\n\nexport { bindModel, getModelBindingMetadata };\nexport type { AnyCommand, AnyModel, ModelBindingIdentity };\n","import type {\n CallAuthority,\n CallController,\n CallDiagnostics,\n CallRunOptions,\n LifetimeLease,\n} from '@opetope/core/internal';\nimport { createCallController, createLifetimeController, reportDetachedError } from '@opetope/core/internal';\n\nimport { getCommandBindingDefinition } from './command';\nimport { ContributionError } from './errors';\nimport { getModelBindingMetadata } from './model-binding';\nimport type { AnyCommand, AnyModel, ModelBindingIdentity } from './model-binding';\n\ntype RuntimeCommandInvoker = {\n readonly run: (input: never, options?: CallRunOptions<unknown>) => Promise<unknown>;\n};\n\ntype CommandRecord = {\n readonly controller: CallController<never, unknown>;\n readonly invoker: RuntimeCommandInvoker;\n};\n\n/** What a mounted contribution grants its components: the models it may read and the commands it may invoke. */\ntype Frame = {\n readonly commandRecords: Map<AnyCommand, CommandRecord>;\n readonly models: Map<AnyModel, unknown>;\n};\n\ntype MountFrameLifecycle = {\n readonly isActive: () => boolean;\n readonly onClose: () => void;\n};\n\ntype MountFrameDiagnostics = {\n readonly active: boolean;\n readonly calls: readonly CallDiagnostics[];\n readonly commandRecords: number;\n readonly models: number;\n};\n\nlet nextMountId = 0;\n\nfunction buildFrame(supplied: readonly ModelBindingIdentity[]): {\n readonly commands: readonly AnyCommand[];\n readonly frame: Frame;\n} {\n const models = new Map<AnyModel, unknown>();\n const commands: AnyCommand[] = [];\n const bound = new Set<AnyCommand>();\n\n for (const candidate of supplied) {\n const binding = getModelBindingMetadata(candidate);\n\n if (models.has(binding.declaration)) {\n throw new ContributionError('duplicate', `Model ${binding.declaration.id} is bound twice in one mount.`);\n }\n\n models.set(binding.declaration, binding.model);\n\n for (const command of binding.commands) {\n // D197: one Command is one command of the mount, however many fields of the models name it. A second name is an\n // alias, not a second command, so it shares the record, the activation and the fence.\n if (bound.has(command)) continue;\n\n bound.add(command);\n commands.push(command);\n }\n }\n\n return { commands: Object.freeze(commands), frame: { commandRecords: new Map(), models } };\n}\n\n/**\n * The lifetime of one mounted contribution. `attach` claims it for the renderer, `detach` schedules the close on the\n * next microtask so a StrictMode remount reuses the same mount, and `close` fences every command it granted (D85).\n */\nclass MountFrameImpl {\n readonly frame: Frame;\n private authority: CallAuthority | undefined;\n private boundCommands: readonly AnyCommand[];\n private closeTicket = 0;\n private readonly isActive: (() => boolean) | undefined;\n private readonly lifetime: ReturnType<typeof createLifetimeController>;\n private onClose: (() => void) | undefined;\n private released = false;\n private rendererAttached = false;\n private readonly renderListeners = new Set<{ readonly listener: () => void }>();\n private state: 'active' | 'closed' | 'closing' | 'detached' = 'detached';\n\n constructor(models: readonly ModelBindingIdentity[], lifecycle?: MountFrameLifecycle) {\n const mountId = ++nextMountId;\n this.lifetime = createLifetimeController({ id: `contribution.${String(mountId)}` });\n this.isActive = lifecycle?.isActive;\n this.onClose = lifecycle?.onClose;\n const { commands, frame } = buildFrame(models);\n this.frame = frame;\n this.boundCommands = commands;\n this.buildCommandRecords(mountId);\n }\n\n attach(): boolean {\n if (this.state === 'closing') {\n this.closeTicket += 1;\n this.state = 'active';\n this.rendererAttached = true;\n\n return true;\n }\n\n if (this.state === 'closed') return false;\n\n if (this.state === 'active') throw new ContributionError('duplicate', 'One contribution mount cannot mount twice.');\n\n const authority = this.createAuthority(this.lifetime.open());\n\n try {\n for (const record of this.frame.commandRecords.values()) record.controller.activate();\n } catch (error) {\n this.authority = authority;\n this.state = 'active';\n this.close();\n\n throw error;\n }\n\n this.authority = authority;\n this.rendererAttached = true;\n this.state = 'active';\n\n return true;\n }\n\n close(): void {\n if (this.state === 'closed') return;\n\n this.state = 'closed';\n this.closeTicket += 1;\n this.lifetime.close();\n this.authority = undefined;\n\n for (const record of this.frame.commandRecords.values()) record.controller.close();\n\n const onClose = this.onClose;\n this.onClose = undefined;\n onClose?.();\n this.publishRenderable();\n\n if (!this.rendererAttached) this.releaseFrame();\n }\n\n detach(): void {\n if (!this.rendererAttached) return;\n\n this.rendererAttached = false;\n\n if (this.state === 'closed') {\n this.releaseFrame();\n\n return;\n }\n\n if (this.state !== 'active') return;\n\n this.state = 'closing';\n const ticket = ++this.closeTicket;\n\n queueMicrotask(() => {\n if (this.state === 'closing' && ticket === this.closeTicket) this.close();\n });\n }\n\n diagnostics(): MountFrameDiagnostics {\n const calls = [...this.frame.commandRecords.values()].map(record => record.controller.diagnostics());\n\n return Object.freeze({\n active: this.state === 'active',\n calls: Object.freeze(calls),\n commandRecords: this.frame.commandRecords.size,\n models: this.frame.models.size,\n });\n }\n\n getRenderableSnapshot = (): boolean => this.state !== 'closed' && (this.isActive === undefined || this.isActive());\n\n releaseClosedFrame(): void {\n if (this.state === 'closed') this.releaseFrame();\n }\n\n subscribeRenderable = (listener: () => void): (() => void) => {\n if (this.state === 'closed') return (): void => undefined;\n\n const registration = { listener };\n this.renderListeners.add(registration);\n let subscribed = true;\n\n return (): void => {\n if (!subscribed) return;\n\n subscribed = false;\n this.renderListeners.delete(registration);\n };\n };\n\n private buildCommandRecords(mountId: number): void {\n let commandIndex = 0;\n\n // `buildFrame` already reduced the models to their distinct Commands, so every command here gets its own record.\n for (const command of this.boundCommands) {\n // Authenticity check only: the binding carries no mode since observe was removed (D71).\n getCommandBindingDefinition(command);\n const controller = createCallController(command, {\n captureAuthority: this.captureAuthority,\n id: `contributionCommand.${String(mountId)}.${String(++commandIndex)}`,\n scheduling: { policy: 'parallel' },\n });\n this.frame.commandRecords.set(command, { controller, invoker: Object.freeze({ run: controller.run }) });\n }\n }\n\n private captureAuthority = (): CallAuthority => {\n const authority = this.authority;\n\n if (this.state !== 'active' || authority === undefined) {\n throw new ContributionError('inactive', 'Contribution mount is not active.');\n }\n\n authority.assertCurrent();\n\n return authority;\n };\n\n private createAuthority(lease: LifetimeLease): CallAuthority {\n return Object.freeze({\n assertCurrent: (): void => {\n if (this.state !== 'active') throw new ContributionError('inactive', 'Contribution mount is not active.');\n\n lease.assertCurrent();\n },\n isCurrent: (): boolean => this.state === 'active' && lease.isCurrent(),\n });\n }\n\n private publishRenderable(): void {\n for (const { listener } of [...this.renderListeners]) {\n try {\n listener();\n } catch (error) {\n reportDetachedError(error);\n }\n }\n }\n\n private releaseFrame(): void {\n if (this.released) return;\n\n this.released = true;\n this.frame.commandRecords.clear();\n this.frame.models.clear();\n this.boundCommands = [];\n this.renderListeners.clear();\n }\n}\n\nexport { MountFrameImpl };\nexport type { Frame };\n","import { useInsertionEffect, useLayoutEffect, useSyncExternalStore } from 'react';\nimport type { PropsWithChildren, ReactElement } from 'react';\n\nimport { FrameContext } from './mount-context';\nimport type { MountFrameImpl } from './mount-frame';\n\nfunction MountProvider({\n children,\n mount,\n}: PropsWithChildren<{ readonly mount: MountFrameImpl }>): ReactElement | null {\n const renderable = useSyncExternalStore(\n mount.subscribeRenderable,\n mount.getRenderableSnapshot,\n mount.getRenderableSnapshot,\n );\n\n useInsertionEffect(() => {\n const attached = mount.attach();\n\n if (!attached) return undefined;\n\n return () => mount.detach();\n }, [mount]);\n\n useLayoutEffect(() => {\n if (!renderable) mount.releaseClosedFrame();\n }, [mount, renderable]);\n\n return renderable ? <FrameContext value={mount.frame}>{children}</FrameContext> : null;\n}\n\nexport { MountProvider };\n","import { memo, useCallback, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type { ComponentType, ReactElement } from 'react';\n\nimport type { DeclarationId, State } from '@opetope/core';\nimport {\n createAggregateError,\n createState,\n getContributionOwner,\n isReadable,\n isResourceView,\n reportDetachedError,\n} from '@opetope/core/internal';\nimport type { ModelIdentity } from '@opetope/core/internal';\nimport { openContributionModels, reportRuntimeFailure, requireContributionModelPlans } from '@opetope/runtime/internal';\nimport type { ContributionModelBundle, RuntimeErrorReporter } from '@opetope/runtime/internal';\n\nimport { bindCommand, isCommandBinding } from './command';\nimport { ContributionIsolation, useContributionErrorContent } from './contribution-isolation';\nimport { bindModel } from './model-binding';\nimport { isResource } from './resource-command';\nimport type { ModelBindingIdentity } from './model-binding';\nimport { MountFrameImpl } from './mount-frame';\nimport { MountProvider } from './mount-provider';\nimport { useReadable } from './readable-hooks';\n\ntype AnyModel = ModelIdentity;\ntype ContributionAuthority = {\n /** The feature whose generation published this contribution (D257). */\n readonly feature?: DeclarationId;\n readonly models: readonly (readonly [AnyModel, unknown])[];\n /** The reporter of the feature that published this contribution: a contained failure is its diagnostic, not ours. */\n readonly reporter?: RuntimeErrorReporter;\n};\ntype ModelFixture = readonly [declaration: AnyModel, model: unknown];\n\ntype ContributionValue = {\n readonly Component: ComponentType<never>;\n readonly models?: readonly object[] | undefined;\n readonly props?: ((slotProps: never) => object) | undefined;\n};\n\ntype ContributionMountProps = {\n readonly authority?: ContributionAuthority | undefined;\n readonly contribution: ContributionValue;\n /** The published entry this mount renders, and the slot it renders in: the identity of a contained failure (D257). */\n readonly contributionId: DeclarationId;\n readonly fixtures?: readonly ModelFixture[];\n readonly slotProps: object;\n readonly targetId: DeclarationId;\n};\n\ntype MountBundle = {\n readonly frame: MountFrameImpl;\n readonly isOpen: () => boolean;\n readonly props: State<object>;\n};\n\ntype MountOwner = {\n readonly authority: ContributionAuthority | undefined;\n bundle: MountBundle | undefined;\n readonly contribution: ContributionValue;\n readonly fixtures: readonly ModelFixture[] | undefined;\n retired: boolean;\n};\n\ntype CommittedMount = {\n readonly bundle: MountBundle;\n readonly owner: MountOwner;\n};\n\nfunction closeOwnedMount(owner: MountOwner): void {\n const bundle = owner.bundle;\n owner.bundle = undefined;\n bundle?.frame.close();\n}\n\n/**\n * Model fields arrive as authentic kernel calls; binding them registers the command records the frame needs. D349: a\n * Resource is none of those and needs none of it — it is a field the selection reads on its own terms, so it travels\n * to the frame unchanged instead of being offered to `bindCommand`, which would refuse it as inauthentic.\n */\nfunction bindFrameModel(declaration: AnyModel, model: unknown): ModelBindingIdentity {\n if (typeof model !== 'object' || model === null) return bindModel(declaration as never, model as never);\n\n const passesThrough = (value: unknown): boolean =>\n isReadable(value) ||\n isResource(value) ||\n isResourceView(value) ||\n typeof value === 'function' ||\n isCommandBinding(value);\n const fields = Object.entries(model).map(([key, value]): readonly [string, unknown] => [\n key,\n passesThrough(value) ? value : bindCommand(value as never),\n ]);\n\n return bindModel(declaration as never, Object.fromEntries(fields) as never);\n}\n\n/**\n * D70: the authority of a contribution belongs to the entry a feature published, not to the value it wrote. One\n * static contribution object may be published by two features, and each mount must read the models of its own.\n */\nfunction contributionAuthority(entry: unknown): ContributionAuthority | undefined {\n return getContributionOwner(entry) as ContributionAuthority | undefined;\n}\n\n/** A mount with no publishing generation behind it: a fixture of a component test grants nothing and reports nowhere. */\nconst unownedContribution: ContributionAuthority = { models: [] };\n\nfunction cleanupFailedMount(close: () => void, cause: unknown): never {\n try {\n close();\n } catch (error) {\n throw createAggregateError([cause, error], 'Contribution mount setup and cleanup failed.', { cause });\n }\n\n throw cause;\n}\n\nfunction contributionModels(\n contribution: ContributionValue,\n slotProps: object,\n fixtures: readonly ModelFixture[],\n owner: ContributionAuthority | undefined,\n): {\n readonly bundle: ContributionModelBundle | undefined;\n readonly models: readonly ModelFixture[];\n readonly props: State<object>;\n} {\n const props = createState(slotProps);\n const { models: granted, reporter } = owner ?? unownedContribution;\n\n try {\n const plans = requireContributionModelPlans(contribution.models);\n const bundle = plans.length === 0 ? undefined : openContributionModels(plans, props, reporter);\n\n return {\n bundle,\n models: [...granted, ...(bundle?.models ?? []), ...fixtures],\n props,\n };\n } catch (error) {\n return cleanupFailedMount(props.close, error);\n }\n}\n\nfunction createMountBundle(\n contribution: ContributionValue,\n slotProps: object,\n fixtures: readonly ModelFixture[],\n authority: ContributionAuthority | undefined,\n): MountBundle {\n const { bundle, models, props } = contributionModels(contribution, slotProps, fixtures, authority);\n let closed = false;\n const close = (): void => {\n if (closed) return;\n\n closed = true;\n\n try {\n void bundle?.close().catch(reportDetachedError);\n } finally {\n props.close();\n }\n };\n try {\n const frame = new MountFrameImpl(\n models.map(([declaration, model]) => bindFrameModel(declaration, model)),\n { isActive: () => !closed, onClose: close },\n );\n\n return { frame, isOpen: () => !closed, props };\n } catch (error) {\n return cleanupFailedMount(close, error);\n }\n}\n\nfunction createComponentElement(Component: ComponentType<never>, props: object): ReactElement {\n const Rendered = Component as ComponentType<object>;\n\n return <Rendered {...props} />;\n}\n\ntype MountedContributionProps = {\n readonly bundle: MountBundle;\n readonly contribution: ContributionValue;\n};\n\n/** Reads the committed props of one live mount: every hook here sees a bundle that already exists. */\nfunction MountedContribution({ bundle, contribution }: MountedContributionProps): ReactElement {\n const committedProps = useReadable(bundle.props);\n const componentProps = useMemo(\n () => (contribution.props === undefined ? committedProps : contribution.props(committedProps as never)),\n [committedProps, contribution],\n );\n\n return (\n <MountProvider mount={bundle.frame}>{createComponentElement(contribution.Component, componentProps)}</MountProvider>\n );\n}\n\n/**\n * D188: a mount is created in commit, never in render. The first pass renders nothing, the layout effect builds the\n * bundle from the props that committed and publishes it, and React flushes that update before paint. A render that\n * is thrown away — StrictMode's double invoke, an abandoned concurrent pass, a suspended sibling — therefore\n * creates no models at all, so there is nothing to sweep, adopt or replace.\n */\nfunction ContributionMount({\n authority,\n contribution,\n fixtures,\n slotProps,\n}: ContributionMountProps): ReactElement | null {\n const owner = useMemo<MountOwner>(\n () => ({ authority, bundle: undefined, contribution, fixtures, retired: false }),\n [authority, contribution, fixtures],\n );\n const [committed, setCommitted] = useState<CommittedMount | undefined>(undefined);\n const bundle = committed?.owner === owner ? committed.bundle : undefined;\n const committedSlotProps = useRef(slotProps);\n\n useLayoutEffect(() => {\n committedSlotProps.current = slotProps;\n });\n\n // Suspense disconnects layout effects while hiding, but insertion cleanup only retires an actual identity.\n // Do not close Readables in insertion: their listeners may update React. A hidden tree has no layout cleanup\n // left to run on unmount, so the microtask also releases a mount that never becomes visible again.\n useInsertionEffect(\n () => () => {\n owner.retired = true;\n queueMicrotask(() => {\n try {\n closeOwnedMount(owner);\n } catch (error) {\n reportDetachedError(error);\n }\n });\n },\n [owner],\n );\n\n // The identity of the contribution owns the mount; a reveal and StrictMode reuse what its first commit created.\n useLayoutEffect(() => {\n const created = (owner.bundle ??= createMountBundle(\n owner.contribution,\n committedSlotProps.current,\n owner.fixtures ?? [],\n owner.authority,\n ));\n setCommitted(current => (current?.owner === owner ? current : { bundle: created, owner }));\n\n return () => {\n if (owner.retired) closeOwnedMount(owner);\n };\n }, [owner]);\n\n // Both the component and its models read the same committed snapshot, published before paint.\n useLayoutEffect(() => {\n if (bundle?.isOpen() === true) bundle.props.set(slotProps);\n }, [bundle, slotProps]);\n\n if (bundle === undefined) return null;\n\n return <MountedContribution bundle={bundle} contribution={contribution} />;\n}\n\n/**\n * D256: every mount is a boundary. The isolation sits above `ContributionMount`, so it contains the render of the\n * component and the commit that builds the mount alike, and a retry rebuilds the mount instead of reusing the bundle\n * that failed. Containment is unconditional; the content a failure shows is the host policy of `ContributionBoundary`.\n */\nfunction IsolatedContributionMount(props: ContributionMountProps): ReactElement {\n const { authority, contribution, contributionId, fixtures, targetId } = props;\n const content = useContributionErrorContent();\n const identity = useMemo(() => ({ authority, contribution, fixtures }), [authority, contribution, fixtures]);\n const feature = authority?.feature;\n const source = useMemo(\n () => ({ contribution: contributionId, feature, target: targetId }),\n [contributionId, feature, targetId],\n );\n const reporter = authority?.reporter;\n const report = useCallback((error: unknown) => reportRuntimeFailure(error, reporter), [reporter]);\n\n return (\n <ContributionIsolation content={content} identity={identity} report={report} source={source}>\n <ContributionMount {...props} />\n </ContributionIsolation>\n );\n}\n\n/**\n * One mount, one memo: `Slot` recreates its children whenever `entries` changes, so publishing or withholding one\n * contribution used to re-render every other mount of that target. The props are the contribution, the slot props\n * and the fixtures, all of which are stable while nothing about that mount changed.\n */\nconst MemoizedContributionMount = memo(IsolatedContributionMount);\n\nexport { contributionAuthority, MemoizedContributionMount as ContributionMount };\nexport type { ContributionValue, ModelFixture };\n"],"names":["FrameContext","createContext","useFrame","frame","useContext","ContributionError","isResource","value","isResourceValue","awaitCancellable","operation","signal","resolve","reject","cancel","CommandError","compatibleAbortReason","error","notifySuccess","options","notification","_a","reportDetachedError","operationInvoker","start","_input","unavailablePage","paginationOf","resource","capability","createResourceInvokers","resourceInvokers","cache","existing","invokers","identity","useSelector","readable","select","selector","isEqual","subscribe","useCallback","listener","instanceRef","useRef","instance","getSelectedSnapshot","useMemo","initialized","sourceSnapshot","selectedSnapshot","nextSource","nextSelected","nextSelectedSnapshot","selected","useSyncExternalStore","useEffect","useReadable","bindingDefinitions","bindCommand","target","isCallTarget","getCommandBindingDefinition","binding","definition","isCommandBinding","modelBindingBrand","modelBindingIdentityBrand","modelBindingMarker","registry","modelFieldValue","declaration","model","field","descriptor","isObservedField","isReadable","isResourceView","snapshotModelFields","commands","fields","bindModel","isModel","getModelBindingMetadata","metadata","nextMountId","buildFrame","supplied","models","bound","candidate","command","MountFrameImpl","lifecycle","mountId","createLifetimeController","authority","record","onClose","ticket","calls","registration","subscribed","commandIndex","controller","createCallController","lease","MountProvider","children","mount","renderable","useInsertionEffect","useLayoutEffect","_jsx","closeOwnedMount","owner","bundle","bindFrameModel","passesThrough","key","contributionAuthority","entry","getContributionOwner","unownedContribution","cleanupFailedMount","close","cause","createAggregateError","contributionModels","contribution","slotProps","fixtures","props","createState","granted","reporter","plans","requireContributionModelPlans","openContributionModels","createMountBundle","closed","createComponentElement","Component","MountedContribution","committedProps","componentProps","ContributionMount","committed","setCommitted","useState","committedSlotProps","created","current","IsolatedContributionMount","contributionId","targetId","content","useContributionErrorContent","feature","source","report","reportRuntimeFailure","ContributionIsolation","MemoizedContributionMount","memo"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contribution-isolation-Bzfbt4iM.js","sources":["../src/errors.ts","../src/contribution-isolation.tsx"],"sourcesContent":["import type { DeclarationId } from '@opetope/core';\nimport { markCancellation } from '@opetope/core/internal';\n\ntype ContributionErrorCode =\n | 'binding-invalid'\n | 'duplicate'\n | 'error-content-failed'\n | 'inactive'\n | 'missing'\n | 'render-failed';\n\n/**\n * D257: what a contained failure says about itself. The mount is the only place that knows all three, and one\n * application reporter serves every feature, so a bare `TypeError` in it would name neither the surface nor the owner.\n */\ntype ContributionErrorDetails = {\n readonly cause?: unknown;\n readonly contribution?: DeclarationId | undefined;\n readonly feature?: DeclarationId | undefined;\n readonly target?: DeclarationId | undefined;\n};\n\n/**\n * One class per subject (D69): after D85 the subject is the contribution mount, which is what grants models and\n * fences commands, so model binding failures are its codes rather than a second class.\n */\nexport class ContributionError extends Error {\n readonly cause: unknown;\n\n /** The published entry, `<feature>.<provides key>`; absent where a failure has no published mount behind it. */\n readonly contribution: DeclarationId | undefined;\n\n readonly feature: DeclarationId | undefined;\n\n override readonly name = 'ContributionError';\n\n readonly target: DeclarationId | undefined;\n\n constructor(\n readonly code: ContributionErrorCode,\n message: string,\n details: ContributionErrorDetails = {},\n ) {\n super(message);\n this.cause = details.cause;\n this.contribution = details.contribution;\n this.feature = details.feature;\n this.target = details.target;\n\n if (code === 'inactive') markCancellation(this);\n }\n}\n\nexport type { ContributionErrorCode };\n","import { Component, createContext, useContext, useRef } from 'react';\nimport type { ReactNode, RefObject } from 'react';\n\nimport type { DeclarationId } from '@opetope/core';\nimport { isCancellation, markCancellation } from '@opetope/core/internal';\n\nimport { ContributionError } from './errors';\n\n/**\n * D257: which contribution failed. The entry id is `<feature>.<provides key>` and the target is the slot it renders\n * in, so one application-wide branch can answer by surface without naming every contribution.\n */\ntype ContributionSource = {\n readonly contribution: DeclarationId;\n readonly feature: DeclarationId | undefined;\n readonly target: DeclarationId;\n};\n\n/**\n * D256: what a failed contribution shows. The shape is the one `FeatureBoundary` already uses for its failure branch,\n * so a host writes one kind of error content for both: the failure itself plus the retry that belongs to it.\n */\ntype ContributionFailure = ContributionSource & {\n readonly error: unknown;\n readonly retry: () => void;\n};\n\ntype ContributionErrorContent = ((failure: ContributionFailure) => ReactNode) | ReactNode;\n\ntype ContributionBoundaryProps = {\n readonly children: ReactNode;\n readonly error: ContributionErrorContent;\n};\n\ntype ContributionErrorContentRef = RefObject<ContributionErrorContent>;\n\nconst noContributionErrorContent: ContributionErrorContentRef = { current: null };\n\n/**\n * One host policy for every mount below it: a contribution whose render or commit throws is replaced by this content\n * instead of reaching the host's own boundary. Containment does not depend on the provider — without it a failed\n * contribution renders nothing — so an application declares the boundary once, at the root, and never per slot.\n *\n * The context carries a stable ref, never the content itself: a host writes the error branch inline, and a context\n * value that changed with it would re-render every mount of the application and undo the per-mount memo (D130).\n * Writing the latest callback into a ref that only readers read is the shape `useModel` already uses for its selector\n * (D214); a mount reads it once, when it is already failing, so content replaced mid-failure lands on the next one.\n */\nconst ErrorContentContext = createContext<ContributionErrorContentRef>(noContributionErrorContent);\n\nfunction ContributionBoundary({ children, error }: ContributionBoundaryProps): ReactNode {\n const content = useRef<ContributionErrorContent>(null);\n content.current = error;\n\n return <ErrorContentContext value={content}>{children}</ErrorContentContext>;\n}\n\nfunction useContributionErrorContent(): ContributionErrorContentRef {\n return useContext(ErrorContentContext);\n}\n\n/**\n * A `RuntimeErrorReporter` takes one argument, so the identity of a contained failure travels inside the error.\n * Cancellation is a brand of the failure, not of a class (D69): a wrapper that dropped it would turn every teardown\n * race a host filters out into a product failure it has to read.\n */\nfunction contributionFailure(\n code: 'error-content-failed' | 'render-failed',\n source: ContributionSource,\n cause: unknown,\n): ContributionError {\n const subject = code === 'render-failed' ? 'Contribution' : 'Error content of contribution';\n const publisher = source.feature === undefined ? '' : ` of feature ${String(source.feature)}`;\n const failure = new ContributionError(\n code,\n `${subject} ${String(source.contribution)}${publisher} failed in slot ${String(source.target)}.`,\n { cause, ...source },\n );\n\n return isCancellation(cause) ? markCancellation(failure) : failure;\n}\n\ntype ContributionErrorProps = {\n readonly content: (failure: ContributionFailure) => ReactNode;\n readonly error: unknown;\n readonly retry: () => void;\n readonly source: ContributionSource;\n};\n\n/** The host callback runs in a child, never in the render of a boundary: a boundary cannot catch its own render. */\nfunction ContributionErrorContent({ content, error, retry, source }: ContributionErrorProps): ReactNode {\n return content({ ...source, error, retry });\n}\n\ntype ContributionFailureViewProps = {\n readonly content: ContributionErrorContentRef;\n readonly error: unknown;\n readonly report: (error: unknown) => void;\n readonly retry: () => void;\n readonly source: ContributionSource;\n};\n\n/**\n * The second stage of containment: error content written by the host is foreign code like any other, and a mount that\n * is already failing must not escalate because its replacement failed too. It exists only after a failure, so the\n * successful path pays for one boundary, not two.\n */\nclass ContributionFailureView extends Component<ContributionFailureViewProps, { readonly failed: boolean }> {\n override state: { readonly failed: boolean } = { failed: false };\n\n static getDerivedStateFromError(): { readonly failed: boolean } {\n return { failed: true };\n }\n\n override componentDidCatch(error: unknown): void {\n this.props.report(contributionFailure('error-content-failed', this.props.source, error));\n }\n\n override render(): ReactNode {\n if (this.state.failed) return null;\n\n const { content, error, retry, source } = this.props;\n const declared = content.current;\n\n return typeof declared === 'function' ? (\n <ContributionErrorContent content={declared} error={error} retry={retry} source={source} />\n ) : (\n declared\n );\n }\n}\n\ntype ContributionIsolationProps = {\n readonly children: ReactNode;\n readonly content: ContributionErrorContentRef;\n /** The mount this boundary belongs to: a replaced contribution starts clean instead of inheriting a dead failure. */\n readonly identity: object;\n readonly report: (error: unknown) => void;\n readonly source: ContributionSource;\n};\n\n/**\n * `failed` is a flag, not the presence of `error`: foreign code may throw `undefined`, and a sentinel would read that\n * as a healthy mount, render the children again and fail again until React gives up.\n */\ntype ContributionIsolationState = {\n readonly error: unknown;\n readonly failed: boolean;\n readonly identity: object | undefined;\n};\n\nclass ContributionIsolation extends Component<ContributionIsolationProps, ContributionIsolationState> {\n override state: ContributionIsolationState = { error: undefined, failed: false, identity: undefined };\n\n static getDerivedStateFromError(error: unknown): Pick<ContributionIsolationState, 'error' | 'failed'> {\n return { error, failed: true };\n }\n\n static getDerivedStateFromProps(\n props: ContributionIsolationProps,\n state: ContributionIsolationState,\n ): ContributionIsolationState | null {\n return state.identity === props.identity ? null : { error: undefined, failed: false, identity: props.identity };\n }\n\n override componentDidCatch(error: unknown): void {\n this.props.report(contributionFailure('render-failed', this.props.source, error));\n }\n\n /** Retry rebuilds the mount: the children remount, so their models are created again rather than reused. */\n private readonly retry = (): void => {\n this.setState(current => (current.failed ? { error: undefined, failed: false, identity: current.identity } : null));\n };\n\n override render(): ReactNode {\n const { error, failed } = this.state;\n\n if (!failed) return this.props.children;\n\n return (\n <ContributionFailureView\n content={this.props.content}\n error={error}\n report={this.props.report}\n retry={this.retry}\n source={this.props.source}\n />\n );\n }\n}\n\nexport { ContributionBoundary, ContributionIsolation, useContributionErrorContent };\nexport type { ContributionBoundaryProps, ContributionErrorContent, ContributionFailure };\n"],"names":["ContributionError","code","message","details","markCancellation","noContributionErrorContent","ErrorContentContext","createContext","ContributionBoundary","children","error","content","useRef","_jsx","useContributionErrorContent","useContext","contributionFailure","source","cause","subject","publisher","failure","isCancellation","ContributionErrorContent","retry","ContributionFailureView","Component","declared","ContributionIsolation","props","state","current","failed"],"mappings":"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"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import type { FeatureDemandSource } from './feature-demand.js';
|
|
3
|
-
/**
|
|
4
|
-
* D177: a branch may be a node or a render callback. The callback receives what only the boundary knows — the ready
|
|
5
|
-
* instance, or the failure with the retry that belongs to this demand — so a ready consumer needs no second
|
|
6
|
-
* `useFeature` and no second lease. A function is never a `ReactNode`, so the two forms cannot be confused.
|
|
7
|
-
*/
|
|
8
|
-
type FeatureBoundaryChildren<Ready> = ((instance: Ready) => ReactNode) | ReactNode;
|
|
9
|
-
type FeatureBoundaryErrorContent = ((context: {
|
|
10
|
-
readonly error: unknown;
|
|
11
|
-
readonly retry: () => void;
|
|
12
|
-
}) => ReactNode) | ReactNode;
|
|
13
|
-
/** The boundary keeps the feature open while it is mounted; its UI enters the host through slots (D85). */
|
|
14
|
-
type FeatureBoundaryProps<Ready = unknown> = {
|
|
15
|
-
readonly children: FeatureBoundaryChildren<Ready>;
|
|
16
|
-
readonly demand: FeatureDemandSource<Ready>;
|
|
17
|
-
readonly error: FeatureBoundaryErrorContent;
|
|
18
|
-
readonly fallback: ReactNode;
|
|
19
|
-
};
|
|
20
|
-
/** One class per subject with the state in `code` (D69): the boundary is its own subject, not a feature failure. */
|
|
21
|
-
declare class FeatureBoundaryError extends Error {
|
|
22
|
-
readonly code: 'missing';
|
|
23
|
-
readonly name = "FeatureBoundaryError";
|
|
24
|
-
constructor(code: 'missing', message: string);
|
|
25
|
-
}
|
|
26
|
-
declare function useFeatureRetry(): () => void;
|
|
27
|
-
declare function FeatureBoundary<Ready>({ children, demand, error, fallback }: FeatureBoundaryProps<Ready>): ReactNode;
|
|
28
|
-
export { FeatureBoundary, FeatureBoundaryError, useFeatureRetry };
|
|
29
|
-
export type { FeatureBoundaryProps };
|
package/dist/feature-demand.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
interface FeatureDemandLease {
|
|
2
|
-
readonly release: () => Promise<void>;
|
|
3
|
-
readonly settled: Promise<void>;
|
|
4
|
-
}
|
|
5
|
-
interface FeatureDemandState<Ready> {
|
|
6
|
-
readonly error: unknown | null;
|
|
7
|
-
readonly instance: Ready | null;
|
|
8
|
-
}
|
|
9
|
-
interface FeatureDemandSource<Ready> {
|
|
10
|
-
acquire(): FeatureDemandLease;
|
|
11
|
-
getState(): FeatureDemandState<Ready>;
|
|
12
|
-
subscribe(listener: () => void): () => void;
|
|
13
|
-
}
|
|
14
|
-
interface FeatureDemandResult<Ready> {
|
|
15
|
-
/** Resolves when the attempt it started has settled, in success and in failure alike (D198). */
|
|
16
|
-
readonly retry: () => Promise<void>;
|
|
17
|
-
readonly state: FeatureDemandState<Ready>;
|
|
18
|
-
}
|
|
19
|
-
declare function useFeature<Ready>(source: FeatureDemandSource<Ready>): FeatureDemandResult<Ready>;
|
|
20
|
-
export { useFeature };
|
|
21
|
-
export type { FeatureDemandLease, FeatureDemandResult, FeatureDemandSource, FeatureDemandState };
|