@opetope/runtime 0.1.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.
Files changed (314) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +345 -0
  4. package/README.ru.md +344 -0
  5. package/dist/application-compiler-edges.d.ts +3 -0
  6. package/dist/application-compiler-edges.js +2 -0
  7. package/dist/application-compiler-edges.js.map +1 -0
  8. package/dist/application-compiler-graph.d.ts +8 -0
  9. package/dist/application-compiler-graph.js +2 -0
  10. package/dist/application-compiler-graph.js.map +1 -0
  11. package/dist/application-compiler.d.ts +116 -0
  12. package/dist/application-compiler.js +2 -0
  13. package/dist/application-compiler.js.map +1 -0
  14. package/dist/application-conditions.d.ts +18 -0
  15. package/dist/application-conditions.js +2 -0
  16. package/dist/application-conditions.js.map +1 -0
  17. package/dist/application-definition.d.ts +30 -0
  18. package/dist/application-definition.js +2 -0
  19. package/dist/application-definition.js.map +1 -0
  20. package/dist/application-error.d.ts +10 -0
  21. package/dist/application-error.js +2 -0
  22. package/dist/application-error.js.map +1 -0
  23. package/dist/application-execution.d.ts +43 -0
  24. package/dist/application-execution.js +2 -0
  25. package/dist/application-execution.js.map +1 -0
  26. package/dist/application-feature-bindings.d.ts +11 -0
  27. package/dist/application-feature-bindings.js +2 -0
  28. package/dist/application-feature-bindings.js.map +1 -0
  29. package/dist/application-feature-instance.d.ts +5 -0
  30. package/dist/application-feature-instance.js +2 -0
  31. package/dist/application-feature-instance.js.map +1 -0
  32. package/dist/application-group-order.d.ts +29 -0
  33. package/dist/application-group-order.js +2 -0
  34. package/dist/application-group-order.js.map +1 -0
  35. package/dist/application-instance-retirement.d.ts +36 -0
  36. package/dist/application-instance-retirement.js +2 -0
  37. package/dist/application-instance-retirement.js.map +1 -0
  38. package/dist/application-open-options.d.ts +29 -0
  39. package/dist/application-open-options.js +2 -0
  40. package/dist/application-open-options.js.map +1 -0
  41. package/dist/application-port-compiler.d.ts +28 -0
  42. package/dist/application-port-compiler.js +2 -0
  43. package/dist/application-port-compiler.js.map +1 -0
  44. package/dist/attachment-call-declaration.d.ts +43 -0
  45. package/dist/attachment-call-declaration.js +2 -0
  46. package/dist/attachment-call-declaration.js.map +1 -0
  47. package/dist/attachment-declaration.d.ts +68 -0
  48. package/dist/attachment-declaration.js +2 -0
  49. package/dist/attachment-declaration.js.map +1 -0
  50. package/dist/attachment-execution.d.ts +9 -0
  51. package/dist/attachment-execution.js +2 -0
  52. package/dist/attachment-execution.js.map +1 -0
  53. package/dist/attachment-retirement-scheduler.d.ts +14 -0
  54. package/dist/attachment-retirement-scheduler.js +2 -0
  55. package/dist/attachment-retirement-scheduler.js.map +1 -0
  56. package/dist/call-option-snapshot.d.ts +20 -0
  57. package/dist/call-option-snapshot.js +2 -0
  58. package/dist/call-option-snapshot.js.map +1 -0
  59. package/dist/compile-call-target-bindings.d.ts +14 -0
  60. package/dist/compile-call-target-bindings.js +2 -0
  61. package/dist/compile-call-target-bindings.js.map +1 -0
  62. package/dist/compile-module-template.d.ts +38 -0
  63. package/dist/compile-module-template.js +2 -0
  64. package/dist/compile-module-template.js.map +1 -0
  65. package/dist/condition-group-execution.d.ts +44 -0
  66. package/dist/condition-group-execution.js +2 -0
  67. package/dist/condition-group-execution.js.map +1 -0
  68. package/dist/condition-override.d.ts +28 -0
  69. package/dist/condition-override.js +2 -0
  70. package/dist/condition-override.js.map +1 -0
  71. package/dist/condition-source.d.ts +10 -0
  72. package/dist/condition-source.js +2 -0
  73. package/dist/condition-source.js.map +1 -0
  74. package/dist/condition-types.d.ts +14 -0
  75. package/dist/condition.d.ts +28 -0
  76. package/dist/condition.js +2 -0
  77. package/dist/condition.js.map +1 -0
  78. package/dist/control-registry.d.ts +56 -0
  79. package/dist/control-registry.js +2 -0
  80. package/dist/control-registry.js.map +1 -0
  81. package/dist/dynamic-scope-child.d.ts +23 -0
  82. package/dist/dynamic-scope-child.js +2 -0
  83. package/dist/dynamic-scope-child.js.map +1 -0
  84. package/dist/dynamic-scope-controller.d.ts +16 -0
  85. package/dist/dynamic-scope-controller.js +2 -0
  86. package/dist/dynamic-scope-controller.js.map +1 -0
  87. package/dist/feature-attachment-authoring-types.d.ts +51 -0
  88. package/dist/feature-attachment-lowering.d.ts +18 -0
  89. package/dist/feature-attachment-lowering.js +2 -0
  90. package/dist/feature-attachment-lowering.js.map +1 -0
  91. package/dist/feature-attachment.d.ts +45 -0
  92. package/dist/feature-attachment.js +2 -0
  93. package/dist/feature-attachment.js.map +1 -0
  94. package/dist/feature-authoring-types.d.ts +196 -0
  95. package/dist/feature-authoring.d.ts +15 -0
  96. package/dist/feature-authoring.js +2 -0
  97. package/dist/feature-authoring.js.map +1 -0
  98. package/dist/feature-body.d.ts +53 -0
  99. package/dist/feature-body.js +2 -0
  100. package/dist/feature-body.js.map +1 -0
  101. package/dist/feature-call-authority.d.ts +8 -0
  102. package/dist/feature-call-authority.js +2 -0
  103. package/dist/feature-call-authority.js.map +1 -0
  104. package/dist/feature-call-types.d.ts +39 -0
  105. package/dist/feature-call.d.ts +18 -0
  106. package/dist/feature-call.js +2 -0
  107. package/dist/feature-call.js.map +1 -0
  108. package/dist/feature-calls.d.ts +6 -0
  109. package/dist/feature-calls.js +2 -0
  110. package/dist/feature-calls.js.map +1 -0
  111. package/dist/feature-contract.d.ts +70 -0
  112. package/dist/feature-contract.js +2 -0
  113. package/dist/feature-contract.js.map +1 -0
  114. package/dist/feature-contribution-model.d.ts +38 -0
  115. package/dist/feature-contribution-model.js +2 -0
  116. package/dist/feature-contribution-model.js.map +1 -0
  117. package/dist/feature-contribution.d.ts +126 -0
  118. package/dist/feature-contribution.js +2 -0
  119. package/dist/feature-contribution.js.map +1 -0
  120. package/dist/feature-definition-api.d.ts +53 -0
  121. package/dist/feature-definition-support.d.ts +21 -0
  122. package/dist/feature-definition-support.js +2 -0
  123. package/dist/feature-definition-support.js.map +1 -0
  124. package/dist/feature-effect.d.ts +26 -0
  125. package/dist/feature-effect.js +2 -0
  126. package/dist/feature-effect.js.map +1 -0
  127. package/dist/feature-event.d.ts +32 -0
  128. package/dist/feature-event.js +2 -0
  129. package/dist/feature-event.js.map +1 -0
  130. package/dist/feature-generation.d.ts +34 -0
  131. package/dist/feature-generation.js +2 -0
  132. package/dist/feature-generation.js.map +1 -0
  133. package/dist/feature-lazy-generation.d.ts +6 -0
  134. package/dist/feature-lazy-generation.js +2 -0
  135. package/dist/feature-lazy-generation.js.map +1 -0
  136. package/dist/feature-lazy.d.ts +44 -0
  137. package/dist/feature-lazy.js +2 -0
  138. package/dist/feature-lazy.js.map +1 -0
  139. package/dist/feature-materialization-binding.d.ts +31 -0
  140. package/dist/feature-materialization-binding.js +2 -0
  141. package/dist/feature-materialization-binding.js.map +1 -0
  142. package/dist/feature-materialization-types.d.ts +45 -0
  143. package/dist/feature-model-dependencies.d.ts +23 -0
  144. package/dist/feature-model-dependencies.js +2 -0
  145. package/dist/feature-model-dependencies.js.map +1 -0
  146. package/dist/feature-model.d.ts +60 -0
  147. package/dist/feature-model.js +2 -0
  148. package/dist/feature-model.js.map +1 -0
  149. package/dist/feature-optional.d.ts +15 -0
  150. package/dist/feature-optional.js +2 -0
  151. package/dist/feature-optional.js.map +1 -0
  152. package/dist/feature-own-lowering.d.ts +22 -0
  153. package/dist/feature-own-lowering.js +2 -0
  154. package/dist/feature-own-lowering.js.map +1 -0
  155. package/dist/feature-port-binding.d.ts +6 -0
  156. package/dist/feature-port-binding.js +2 -0
  157. package/dist/feature-port-binding.js.map +1 -0
  158. package/dist/feature-port.d.ts +66 -0
  159. package/dist/feature-port.js +2 -0
  160. package/dist/feature-port.js.map +1 -0
  161. package/dist/feature-record.d.ts +6 -0
  162. package/dist/feature-record.js +2 -0
  163. package/dist/feature-record.js.map +1 -0
  164. package/dist/feature-resource.d.ts +29 -0
  165. package/dist/feature-resource.js +2 -0
  166. package/dist/feature-resource.js.map +1 -0
  167. package/dist/feature-scope-types.d.ts +35 -0
  168. package/dist/feature-scope.d.ts +29 -0
  169. package/dist/feature-scope.js +2 -0
  170. package/dist/feature-scope.js.map +1 -0
  171. package/dist/feature-stream.d.ts +37 -0
  172. package/dist/feature-stream.js +2 -0
  173. package/dist/feature-stream.js.map +1 -0
  174. package/dist/feature-timers.d.ts +14 -0
  175. package/dist/feature-timers.js +2 -0
  176. package/dist/feature-timers.js.map +1 -0
  177. package/dist/index.d.ts +19 -0
  178. package/dist/index.js +2 -0
  179. package/dist/index.js.map +1 -0
  180. package/dist/inspection-activity-protocol.d.ts +63 -0
  181. package/dist/inspection-activity.d.ts +54 -0
  182. package/dist/inspection-activity.js +2 -0
  183. package/dist/inspection-activity.js.map +1 -0
  184. package/dist/inspection-diff.d.ts +10 -0
  185. package/dist/inspection-diff.js +2 -0
  186. package/dist/inspection-diff.js.map +1 -0
  187. package/dist/inspection-module-activity.d.ts +4 -0
  188. package/dist/inspection-module-activity.js +2 -0
  189. package/dist/inspection-module-activity.js.map +1 -0
  190. package/dist/inspection-observer.d.ts +38 -0
  191. package/dist/inspection-observer.js +2 -0
  192. package/dist/inspection-observer.js.map +1 -0
  193. package/dist/inspection-plan.d.ts +33 -0
  194. package/dist/inspection-plan.js +2 -0
  195. package/dist/inspection-plan.js.map +1 -0
  196. package/dist/inspection-protocol.d.ts +333 -0
  197. package/dist/inspection-protocol.js +2 -0
  198. package/dist/inspection-protocol.js.map +1 -0
  199. package/dist/inspection-registry.d.ts +41 -0
  200. package/dist/inspection-registry.js +2 -0
  201. package/dist/inspection-registry.js.map +1 -0
  202. package/dist/inspection-session.d.ts +92 -0
  203. package/dist/inspection-session.js +2 -0
  204. package/dist/inspection-session.js.map +1 -0
  205. package/dist/inspection-snapshot.d.ts +4 -0
  206. package/dist/inspection-snapshot.js +2 -0
  207. package/dist/inspection-snapshot.js.map +1 -0
  208. package/dist/inspection-state.d.ts +91 -0
  209. package/dist/inspection-state.js +2 -0
  210. package/dist/inspection-state.js.map +1 -0
  211. package/dist/instance-demand.d.ts +31 -0
  212. package/dist/instance-demand.js +2 -0
  213. package/dist/instance-demand.js.map +1 -0
  214. package/dist/internal.d.ts +41 -0
  215. package/dist/internal.js +2 -0
  216. package/dist/internal.js.map +1 -0
  217. package/dist/keyed-scope-controller.d.ts +11 -0
  218. package/dist/keyed-scope-controller.js +2 -0
  219. package/dist/keyed-scope-controller.js.map +1 -0
  220. package/dist/model-kernel.d.ts +18 -0
  221. package/dist/model-kernel.js +2 -0
  222. package/dist/model-kernel.js.map +1 -0
  223. package/dist/module-call-context.d.ts +7 -0
  224. package/dist/module-call-context.js +2 -0
  225. package/dist/module-call-context.js.map +1 -0
  226. package/dist/module-call-runtime.d.ts +21 -0
  227. package/dist/module-call-runtime.js +2 -0
  228. package/dist/module-call-runtime.js.map +1 -0
  229. package/dist/module-generation.d.ts +57 -0
  230. package/dist/module-generation.js +2 -0
  231. package/dist/module-generation.js.map +1 -0
  232. package/dist/module-instance-types.d.ts +156 -0
  233. package/dist/module-instance.d.ts +19 -0
  234. package/dist/module-instance.js +2 -0
  235. package/dist/module-instance.js.map +1 -0
  236. package/dist/module-runtime-identity.d.ts +4 -0
  237. package/dist/module-runtime-identity.js +2 -0
  238. package/dist/module-runtime-identity.js.map +1 -0
  239. package/dist/module-scope-open.d.ts +4 -0
  240. package/dist/module-scope-open.js +2 -0
  241. package/dist/module-scope-open.js.map +1 -0
  242. package/dist/module-scope-retirement.d.ts +3 -0
  243. package/dist/module-scope-retirement.js +2 -0
  244. package/dist/module-scope-retirement.js.map +1 -0
  245. package/dist/module-template-ir.d.ts +59 -0
  246. package/dist/owner-generation-retirement.d.ts +6 -0
  247. package/dist/owner-generation-retirement.js +2 -0
  248. package/dist/owner-generation-retirement.js.map +1 -0
  249. package/dist/owner-generation-state.d.ts +123 -0
  250. package/dist/owner-generation-state.js +2 -0
  251. package/dist/owner-generation-state.js.map +1 -0
  252. package/dist/owner-generation.d.ts +16 -0
  253. package/dist/owner-generation.js +2 -0
  254. package/dist/owner-generation.js.map +1 -0
  255. package/dist/public-module-definition.d.ts +9 -0
  256. package/dist/public-module-definition.js +2 -0
  257. package/dist/public-module-definition.js.map +1 -0
  258. package/dist/public-module-instance.d.ts +6 -0
  259. package/dist/public-module-instance.js +2 -0
  260. package/dist/public-module-instance.js.map +1 -0
  261. package/dist/public-module-retirement-diagnostics.d.ts +5 -0
  262. package/dist/public-module-retirement-diagnostics.js +2 -0
  263. package/dist/public-module-retirement-diagnostics.js.map +1 -0
  264. package/dist/public-module-retirement.d.ts +3 -0
  265. package/dist/public-module-retirement.js +2 -0
  266. package/dist/public-module-retirement.js.map +1 -0
  267. package/dist/public-module-scope.d.ts +5 -0
  268. package/dist/public-module-scope.js +2 -0
  269. package/dist/public-module-scope.js.map +1 -0
  270. package/dist/public-module-state.d.ts +28 -0
  271. package/dist/public-module-state.js +2 -0
  272. package/dist/public-module-state.js.map +1 -0
  273. package/dist/public-module-types.d.ts +295 -0
  274. package/dist/public-module.d.ts +4 -0
  275. package/dist/resource-cache.d.ts +12 -0
  276. package/dist/resource-cache.js +2 -0
  277. package/dist/resource-cache.js.map +1 -0
  278. package/dist/resource-controller.d.ts +29 -0
  279. package/dist/resource-controller.js +2 -0
  280. package/dist/resource-controller.js.map +1 -0
  281. package/dist/resource-policy.d.ts +16 -0
  282. package/dist/resource-policy.js +2 -0
  283. package/dist/resource-policy.js.map +1 -0
  284. package/dist/resource-snapshot.d.ts +12 -0
  285. package/dist/resource-snapshot.js +2 -0
  286. package/dist/resource-snapshot.js.map +1 -0
  287. package/dist/resource-types.d.ts +3 -0
  288. package/dist/runtime-error-reporting.d.ts +4 -0
  289. package/dist/runtime-error-reporting.js +2 -0
  290. package/dist/runtime-error-reporting.js.map +1 -0
  291. package/dist/stream-backpressure.d.ts +18 -0
  292. package/dist/stream-backpressure.js +2 -0
  293. package/dist/stream-backpressure.js.map +1 -0
  294. package/dist/stream-cleanup.d.ts +17 -0
  295. package/dist/stream-cleanup.js +2 -0
  296. package/dist/stream-cleanup.js.map +1 -0
  297. package/dist/stream-controller-types.d.ts +51 -0
  298. package/dist/stream-controller.d.ts +5 -0
  299. package/dist/stream-controller.js +2 -0
  300. package/dist/stream-controller.js.map +1 -0
  301. package/docs/agent-guide.md +214 -0
  302. package/docs/agent-guide.ru.md +208 -0
  303. package/docs/cookbook.md +734 -0
  304. package/docs/cookbook.ru.md +729 -0
  305. package/docs/decisions.md +1437 -0
  306. package/docs/devtools.md +423 -0
  307. package/docs/devtools.ru.md +419 -0
  308. package/docs/how-it-works.md +521 -0
  309. package/docs/how-it-works.ru.md +495 -0
  310. package/docs/releases.md +78 -0
  311. package/docs/releases.ru.md +78 -0
  312. package/docs/spec.md +874 -0
  313. package/docs/spec.ru.md +884 -0
  314. package/package.json +72 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * The live half of the observation port: what the application has open right now, projected into the protocol.
3
+ *
4
+ * Two kinds of fact live here. An instance state and a group state are *authoritative*: only the lifecycle can know
5
+ * them, so they arrive through the observer hooks. A condition, a port, a host contract, a contribution and every
6
+ * dependency edge are *derived*: they are recomputed by pulling — never by subscribing, because a subscription would
7
+ * change the application's demand and `docs/devtools.md` §3.4 forbids that.
8
+ *
9
+ * Every commit recomputes the derived half and diffs it against the published one, so a frame carries whole changed
10
+ * records and nothing else (`docs/devtools.md` §5.1). The node and edge maps keep insertion order, which is the order a consumer's
11
+ * fold reproduces, so `getSnapshot()` and "snapshot plus frames" stay literally equal.
12
+ */
13
+ import type { Readable } from '@opetope/core';
14
+ import type { CompiledApplicationPlanIR } from './application-compiler.js';
15
+ import type { Condition } from './condition.js';
16
+ import type { ControllableCondition } from './condition-override.js';
17
+ import type { ApplicationActivity } from './inspection-activity.js';
18
+ import type { ConditionGroupState, DiagnosticCauseRef, DiagnosticNodeId, DiagnosticOperation, FeatureInstanceState, RuntimeStateSnapshot } from './inspection-protocol.js';
19
+ type InspectionSources = Readonly<{
20
+ activity: ApplicationActivity;
21
+ applicationId: DiagnosticNodeId;
22
+ boundContracts: ReadonlySet<object>;
23
+ /** The debug override of each condition, so a group can report `force-inactive` next to its own source (D176). */
24
+ conditionControls: ReadonlyMap<string, ControllableCondition>;
25
+ conditionReadables: ReadonlyMap<Condition, Readable<boolean>>;
26
+ plan: CompiledApplicationPlanIR;
27
+ }>;
28
+ declare class InspectionState {
29
+ private readonly sources;
30
+ private cachedSnapshot;
31
+ private readonly contributionsByFeature;
32
+ private readonly edges;
33
+ private edgesDirty;
34
+ private readonly groupCauses;
35
+ private readonly groupStates;
36
+ private readonly instances;
37
+ private readonly nodes;
38
+ private readonly retired;
39
+ constructor(sources: InspectionSources);
40
+ /** A retired instance leaves the live world; its generation number is kept so the next open can name it. */
41
+ dropInstance(featureIndex: number): void;
42
+ hasInstance(featureIndex: number): boolean;
43
+ openInstance(featureIndex: number, cause: DiagnosticCauseRef | undefined): void;
44
+ /** Recomputes the derived half, applies the difference to the published graph and returns what changed. */
45
+ reconcile(): readonly DiagnosticOperation[];
46
+ setGroupState(groupId: string, state: ConditionGroupState, cause: DiagnosticCauseRef | undefined): void;
47
+ setInstanceState(featureIndex: number, state: FeatureInstanceState, cause: DiagnosticCauseRef | undefined): void;
48
+ snapshot(): RuntimeStateSnapshot;
49
+ /** T16: the IR names contributor and target in one edge; the projection makes the contribution a node between them. */
50
+ private addContributionEdges;
51
+ private addEdge;
52
+ private addHardEdge;
53
+ private addImportEdge;
54
+ /** Every live edge hangs off a live instance: a consumer that is gone has no dependency to report. */
55
+ private addInstanceEdges;
56
+ /** T13: one IR requirement edge, three protocol edges — hard, weak with a provider, and weak without one. */
57
+ private addRequirementEdge;
58
+ private addWeakEdge;
59
+ private buildEdges;
60
+ private buildNodes;
61
+ private conditionHolds;
62
+ private conditionNodes;
63
+ /**
64
+ * D93: a condition computed from a feature reads `false` while that feature has no ready instance, and the panel
65
+ * shows that as `source-closed`. The declaration itself is a frozen `{ id }`, so `from` is resolved through the
66
+ * Record the runtime keeps, not off the condition object.
67
+ */
68
+ /** The product truth of one condition, read past the debug override the control port may have set (D176). */
69
+ private conditionSourceHolds;
70
+ private conditionState;
71
+ private contributionNodes;
72
+ /**
73
+ * D79: a contribution whose `when` reads `false` stays published and valid while the target omits it from
74
+ * `entries`, so "published but invisible" is read off the target rather than guessed.
75
+ */
76
+ private contributionState;
77
+ private diffEdges;
78
+ private diffNodes;
79
+ private groupNodes;
80
+ private hostContractNodes;
81
+ private hostContractState;
82
+ private instanceNodes;
83
+ private isReady;
84
+ private lookupOfFeature;
85
+ private portNodes;
86
+ /** T8: the provider is chosen at compile time, so the only live question is whether it has a ready instance. */
87
+ private portState;
88
+ private providerNodeId;
89
+ }
90
+ export { InspectionState };
91
+ export type { InspectionSources };
@@ -0,0 +1,2 @@
1
+ import{requireConditionRecord as h}from"./condition.js";import{sameRecord as c}from"./inspection-diff.js";import{nodeIds as i,diagnosticEdgeId as a}from"./inspection-plan.js";import{snapshotRuntimeState as p}from"./inspection-snapshot.js";function u(d,e){return e===void 0?d:{...d,cause:e}}class f{sources;cachedSnapshot;contributionsByFeature=new Map;edges=new Map;edgesDirty=!0;groupCauses=new Map;groupStates=new Map;instances=new Map;nodes=new Map;retired=new Map;constructor(e){this.sources=e;for(const t of e.plan.contributions){const n=this.contributionsByFeature.get(t.contributorFeatureIndex);n===void 0?this.contributionsByFeature.set(t.contributorFeatureIndex,[t]):n.push(t)}}dropInstance(e){const t=this.instances.get(e);t!==void 0&&(this.retired.set(e,t.generation),this.instances.delete(e),this.edgesDirty=!0)}hasInstance(e){return this.instances.has(e)}openInstance(e,t){var s;const n=this.sources.plan.features[e];if(n===void 0)return;const o=this.retired.get(e);this.edgesDirty=!0,this.instances.set(e,{cause:t,featureId:n.featureId,generation:((s=this.sources.activity.owners.get(e))==null?void 0:s.identity.generation)??(o??0)+1,group:n.owner.kind==="group"?i.group(n.owner.groupId):void 0,previous:o,state:{kind:"opening"}})}reconcile(){const e=this.diffNodes(this.buildNodes()),t=this.edgesDirty?this.diffEdges(this.buildEdges()):[];return this.edgesDirty=!1,(e.length>0||t.length>0)&&(this.cachedSnapshot=void 0),[...e,...t]}setGroupState(e,t,n){this.groupStates.set(e,t),this.groupCauses.set(e,n)}setInstanceState(e,t,n){const o=this.instances.get(e);o!==void 0&&(o.state=t,this.edgesDirty=!0,o.cause=n??o.cause)}snapshot(){return this.cachedSnapshot??(this.cachedSnapshot=p(this.nodes.values(),this.edges.values())),this.cachedSnapshot}addContributionEdges(e,t,n){const o=i.contribution(t.contributionId);this.addEdge(e,"owns",n,o),this.addEdge(e,"contributes-to",o,i.target(t.targetId))}addEdge(e,t,n,o){const s=a(t,n,o);e.set(s,{from:n,id:s,kind:t,to:o})}addHardEdge(e,t,n,o,s){const r=a(t,n,o);e.set(r,{from:n,id:r,kind:t,pending:s,to:o})}addImportEdge(e,t,n){const{provider:o}=t;if(o.kind==="absent"){this.addWeakEdge(e,"absent-import",i.absentProvider(o.contractId),n,"missing");return}const s=o.kind==="feature"?this.providerNodeId(o.featureIndex):i.hostContract(o.contractId),r=o.kind==="feature"?this.lookupOfFeature(o.featureIndex):this.sources.boundContracts.has(o.contract)?"found":"missing";if(t.optional){this.addWeakEdge(e,"optional-import",s,n,r);return}if(t.demand==="onDemand"){this.addEdge(e,"on-demand-import",s,n);return}this.addHardEdge(e,"hard-import",s,n,r==="missing")}addInstanceEdges(e,t,n){const o=i.instance(n.featureId),s=this.sources.plan.features[t];this.addEdge(e,"owns",n.group??this.sources.applicationId,o);for(const r of s.imports)this.addImportEdge(e,r,o);for(const r of s.requirements)this.addRequirementEdge(e,r,o);for(const r of this.contributionsByFeature.get(t)??[])this.addContributionEdges(e,r,o)}addRequirementEdge(e,t,n){const o=i.port(t.portId);if(t.provider===void 0){this.addWeakEdge(e,"absent-port",o,n,"missing");return}if(t.optional){this.addWeakEdge(e,"optional-port",o,n,this.lookupOfFeature(t.provider.featureIndex));return}this.addHardEdge(e,"requires-port",o,n,!this.isReady(t.provider.featureIndex))}addWeakEdge(e,t,n,o,s){const r=a(t,n,o);e.set(r,{from:n,id:r,kind:t,lookup:s,to:o})}buildEdges(){const e=new Map;for(const[t,n]of this.instances)this.addInstanceEdges(e,t,n);return e}buildNodes(){const e=new Map;for(const t of this.conditionNodes())e.set(t.id,t);for(const t of this.groupNodes())e.set(t.id,t);for(const t of this.instanceNodes())e.set(t.id,t);for(const t of this.contributionNodes())e.set(t.id,t);for(const t of this.portNodes())e.set(t.id,t);for(const t of this.hostContractNodes())e.set(t.id,t);return e}conditionHolds(e){const t=this.sources.conditionReadables.get(e);return t!==void 0&&this.conditionState(e,t).kind==="true"}conditionNodes(){const e=[];for(const[t,n]of this.sources.conditionReadables)e.push({declaration:i.condition(t.id),id:i.condition(t.id),kind:"condition",label:t.id,state:this.conditionState(t,n)});return e}conditionSourceHolds(e){const t=this.sources.conditionControls.get(e.id);return t!==void 0?t.source():this.conditionHolds(e)}conditionState(e,t){var s;const n=h(e).from,o=n===void 0?-1:this.sources.plan.features.findIndex(r=>r.definition===n);return o>=0&&((s=this.instances.get(o))==null?void 0:s.state.kind)!=="ready"?{kind:"source-closed"}:t.getSnapshot()?{kind:"true"}:{kind:"false"}}contributionNodes(){const e=[];for(const t of this.sources.plan.contributions){const n=this.instances.get(t.contributorFeatureIndex);n!==void 0&&e.push({contributor:i.instance(n.featureId),declaration:i.contribution(t.contributionId),id:i.contribution(t.contributionId),kind:"contribution",label:t.contributionId,state:this.contributionState(n,t.target,t.contributionId),target:i.target(t.targetId)})}return e}contributionState(e,t,n){return e.state.kind==="opening"?{kind:"pending"}:e.state.kind!=="ready"?{kind:"withdrawn"}:t.entries.getSnapshot().some(s=>s.id===n)?{kind:"published"}:{kind:"withheld"}}diffEdges(e){const t=[];for(const n of[...this.edges.keys()])e.has(n)||(this.edges.delete(n),t.push({id:n,op:"remove-edge"}));for(const[n,o]of e){if(c(this.edges.get(n),o))continue;const s=Object.freeze(o);this.edges.set(n,s),t.push({edge:s,op:"upsert-edge"})}return t}diffNodes(e){const t=[];for(const n of[...this.nodes.keys()])e.has(n)||(this.nodes.delete(n),t.push({id:n,op:"remove-node"}));for(const[n,o]of e){if(c(this.nodes.get(n),o))continue;const s=Object.freeze(o);this.nodes.set(n,s),t.push({node:s,op:"upsert-node"})}return t}groupNodes(){return this.sources.plan.groups.map(e=>{const t=e.conditions.every(s=>this.conditionHolds(s))?"active":"inactive",n=e.conditions.some(s=>{var r;return((r=this.sources.conditionControls.get(s.id))==null?void 0:r.overridden())===!0}),o=e.conditions.every(s=>this.conditionSourceHolds(s))?"active":"inactive";return u({declaration:i.group(e.groupId),desired:{effective:t,override:n?"force-inactive":"none",source:o},id:i.group(e.groupId),kind:"condition-group",label:`when ${e.conditions.map(s=>s.id).join(" & ")}`,state:this.groupStates.get(e.groupId)??{kind:"inactive",reason:"condition-inactive"}},this.groupCauses.get(e.groupId))})}hostContractNodes(){const e=new Map;for(const t of this.sources.plan.imports)t.provider.kind!=="application-input"||e.has(t.contractId)||e.set(t.contractId,{declaration:i.hostContract(t.contractId),id:i.hostContract(t.contractId),kind:"host-contract",label:t.contractId,state:this.hostContractState(t.contract,t.demand)});return[...e.values()]}hostContractState(e,t){return t==="onDemand"?{kind:"deferred"}:this.sources.boundContracts.has(e)?{kind:"bound"}:{kind:"unbound"}}instanceNodes(){const e=[];for(const t of this.instances.values())e.push(u({declaration:i.feature(t.featureId),generation:t.generation,...t.group===void 0?{}:{group:t.group},id:i.instance(t.featureId),kind:"feature-instance",label:t.featureId,...t.previous===void 0?{}:{previous:t.previous},state:t.state},t.cause));return e}isReady(e){var t;return((t=this.instances.get(e))==null?void 0:t.state.kind)==="ready"}lookupOfFeature(e){return this.isReady(e)?"found":"missing"}portNodes(){var t;const e=new Map;for(const n of this.sources.plan.requirements)e.has(n.portId)||e.set(n.portId,{declaration:i.port(n.portId),id:i.port(n.portId),kind:"port",label:n.portId,state:this.portState((t=n.provider)==null?void 0:t.featureIndex)});for(const n of this.sources.plan.providers)e.has(n.portId)||e.set(n.portId,{declaration:i.port(n.portId),id:i.port(n.portId),kind:"port",label:n.portId,state:this.portState(n.featureIndex)});return[...e.values()]}portState(e){if(e===void 0)return{kind:"absent"};const t=this.sources.plan.features[e],n=this.instances.get(e);return(n==null?void 0:n.state.kind)==="ready"?{instance:i.instance(n.featureId),kind:"available"}:{kind:"unavailable",provider:i.feature((t==null?void 0:t.featureId)??String(e))}}providerNodeId(e){var n;const t=this.instances.get(e);return t!==void 0?i.instance(t.featureId):i.feature(((n=this.sources.plan.features[e])==null?void 0:n.featureId)??String(e))}}export{f as InspectionState};
2
+ //# sourceMappingURL=inspection-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspection-state.js","sources":["../src/inspection-state.ts"],"sourcesContent":["/**\n * The live half of the observation port: what the application has open right now, projected into the protocol.\n *\n * Two kinds of fact live here. An instance state and a group state are *authoritative*: only the lifecycle can know\n * them, so they arrive through the observer hooks. A condition, a port, a host contract, a contribution and every\n * dependency edge are *derived*: they are recomputed by pulling — never by subscribing, because a subscription would\n * change the application's demand and `docs/devtools.md` §3.4 forbids that.\n *\n * Every commit recomputes the derived half and diffs it against the published one, so a frame carries whole changed\n * records and nothing else (`docs/devtools.md` §5.1). The node and edge maps keep insertion order, which is the order a consumer's\n * fold reproduces, so `getSnapshot()` and \"snapshot plus frames\" stay literally equal.\n */\n\nimport type { Readable } from '@opetope/core';\n\nimport type { CompiledApplicationPlanIR } from './application-compiler';\nimport { requireConditionRecord } from './condition';\nimport type { Condition } from './condition';\nimport type { ControllableCondition } from './condition-override';\nimport type { ApplicationActivity } from './inspection-activity';\nimport { sameRecord } from './inspection-diff';\nimport { diagnosticEdgeId, nodeIds } from './inspection-plan';\nimport type {\n ConditionGroupRuntimeNode,\n ConditionGroupState,\n ConditionRuntimeNode,\n ContributionRuntimeNode,\n ContributionState,\n DesiredAxis,\n DiagnosticCauseRef,\n DiagnosticEdge,\n DiagnosticEdgeId,\n DiagnosticNodeId,\n DiagnosticOperation,\n DiagnosticRuntimeNode,\n FeatureInstanceNode,\n FeatureInstanceState,\n HostContractRuntimeNode,\n HostContractState,\n PortRuntimeNode,\n PortState,\n RuntimeStateSnapshot,\n WeakEdgeState,\n} from './inspection-protocol';\nimport { snapshotRuntimeState } from './inspection-snapshot';\n\ntype InstanceRecord = {\n cause: DiagnosticCauseRef | undefined;\n readonly featureId: string;\n readonly generation: number;\n readonly group: DiagnosticNodeId | undefined;\n readonly previous: number | undefined;\n state: FeatureInstanceState;\n};\n\ntype InspectionSources = Readonly<{\n activity: ApplicationActivity;\n applicationId: DiagnosticNodeId;\n boundContracts: ReadonlySet<object>;\n /** The debug override of each condition, so a group can report `force-inactive` next to its own source (D176). */\n conditionControls: ReadonlyMap<string, ControllableCondition>;\n conditionReadables: ReadonlyMap<Condition, Readable<boolean>>;\n plan: CompiledApplicationPlanIR;\n}>;\n\nfunction withCause<Node extends object>(node: Node, cause: DiagnosticCauseRef | undefined): Node {\n return cause === undefined ? node : { ...node, cause };\n}\n\nclass InspectionState {\n private cachedSnapshot: RuntimeStateSnapshot | undefined;\n private readonly contributionsByFeature = new Map<number, CompiledApplicationPlanIR['contributions'][number][]>();\n private readonly edges = new Map<DiagnosticEdgeId, DiagnosticEdge>();\n private edgesDirty = true;\n\n private readonly groupCauses = new Map<string, DiagnosticCauseRef | undefined>();\n\n private readonly groupStates = new Map<string, ConditionGroupState>();\n\n private readonly instances = new Map<number, InstanceRecord>();\n\n private readonly nodes = new Map<DiagnosticNodeId, DiagnosticRuntimeNode>();\n\n private readonly retired = new Map<number, number>();\n\n public constructor(private readonly sources: InspectionSources) {\n for (const entry of sources.plan.contributions) {\n const entries = this.contributionsByFeature.get(entry.contributorFeatureIndex);\n\n if (entries === undefined) this.contributionsByFeature.set(entry.contributorFeatureIndex, [entry]);\n else entries.push(entry);\n }\n }\n\n /** A retired instance leaves the live world; its generation number is kept so the next open can name it. */\n public dropInstance(featureIndex: number): void {\n const record = this.instances.get(featureIndex);\n\n if (record === undefined) return;\n\n this.retired.set(featureIndex, record.generation);\n this.instances.delete(featureIndex);\n this.edgesDirty = true;\n }\n\n public hasInstance(featureIndex: number): boolean {\n return this.instances.has(featureIndex);\n }\n\n public openInstance(featureIndex: number, cause: DiagnosticCauseRef | undefined): void {\n const feature = this.sources.plan.features[featureIndex];\n\n if (feature === undefined) return;\n\n const previous = this.retired.get(featureIndex);\n this.edgesDirty = true;\n\n this.instances.set(featureIndex, {\n cause,\n featureId: feature.featureId,\n generation: this.sources.activity.owners.get(featureIndex)?.identity.generation ?? (previous ?? 0) + 1,\n group: feature.owner.kind === 'group' ? nodeIds.group(feature.owner.groupId) : undefined,\n previous,\n state: { kind: 'opening' },\n });\n }\n\n /** Recomputes the derived half, applies the difference to the published graph and returns what changed. */\n public reconcile(): readonly DiagnosticOperation[] {\n // Conditions and visibility remain pull-based. Edges depend only on instance identity/readiness,\n // so an activity read must not rebuild the immutable topology for every owner.\n const nodes = this.diffNodes(this.buildNodes());\n const edges = this.edgesDirty ? this.diffEdges(this.buildEdges()) : [];\n this.edgesDirty = false;\n\n if (nodes.length > 0 || edges.length > 0) this.cachedSnapshot = undefined;\n\n return [...nodes, ...edges];\n }\n\n public setGroupState(groupId: string, state: ConditionGroupState, cause: DiagnosticCauseRef | undefined): void {\n this.groupStates.set(groupId, state);\n this.groupCauses.set(groupId, cause);\n }\n\n public setInstanceState(\n featureIndex: number,\n state: FeatureInstanceState,\n cause: DiagnosticCauseRef | undefined,\n ): void {\n const record = this.instances.get(featureIndex);\n\n if (record === undefined) return;\n\n record.state = state;\n this.edgesDirty = true;\n record.cause = cause ?? record.cause;\n }\n\n public snapshot(): RuntimeStateSnapshot {\n this.cachedSnapshot ??= snapshotRuntimeState(this.nodes.values(), this.edges.values());\n\n return this.cachedSnapshot;\n }\n\n /** T16: the IR names contributor and target in one edge; the projection makes the contribution a node between them. */\n private addContributionEdges(\n edges: Map<DiagnosticEdgeId, DiagnosticEdge>,\n contribution: CompiledApplicationPlanIR['contributions'][number],\n consumer: DiagnosticNodeId,\n ): void {\n const node = nodeIds.contribution(contribution.contributionId);\n this.addEdge(edges, 'owns', consumer, node);\n this.addEdge(edges, 'contributes-to', node, nodeIds.target(contribution.targetId));\n }\n\n private addEdge(\n edges: Map<DiagnosticEdgeId, DiagnosticEdge>,\n kind: 'contributes-to' | 'on-demand-import' | 'owns',\n from: DiagnosticNodeId,\n to: DiagnosticNodeId,\n ): void {\n const id = diagnosticEdgeId(kind, from, to);\n edges.set(id, { from, id, kind, to });\n }\n\n private addHardEdge(\n edges: Map<DiagnosticEdgeId, DiagnosticEdge>,\n kind: 'hard-import' | 'requires-port',\n from: DiagnosticNodeId,\n to: DiagnosticNodeId,\n pending: boolean,\n ): void {\n const id = diagnosticEdgeId(kind, from, to);\n edges.set(id, { from, id, kind, pending, to });\n }\n\n private addImportEdge(\n edges: Map<DiagnosticEdgeId, DiagnosticEdge>,\n binding: CompiledApplicationPlanIR['imports'][number],\n consumer: DiagnosticNodeId,\n ): void {\n const { provider } = binding;\n\n if (provider.kind === 'absent') {\n this.addWeakEdge(edges, 'absent-import', nodeIds.absentProvider(provider.contractId), consumer, 'missing');\n\n return;\n }\n\n const from =\n provider.kind === 'feature'\n ? this.providerNodeId(provider.featureIndex)\n : nodeIds.hostContract(provider.contractId);\n const found: WeakEdgeState =\n provider.kind === 'feature'\n ? this.lookupOfFeature(provider.featureIndex)\n : this.sources.boundContracts.has(provider.contract)\n ? 'found'\n : 'missing';\n\n if (binding.optional) {\n this.addWeakEdge(edges, 'optional-import', from, consumer, found);\n\n return;\n }\n\n if (binding.demand === 'onDemand') {\n this.addEdge(edges, 'on-demand-import', from, consumer);\n\n return;\n }\n\n this.addHardEdge(edges, 'hard-import', from, consumer, found === 'missing');\n }\n\n /** Every live edge hangs off a live instance: a consumer that is gone has no dependency to report. */\n private addInstanceEdges(\n edges: Map<DiagnosticEdgeId, DiagnosticEdge>,\n featureIndex: number,\n record: InstanceRecord,\n ): void {\n const consumer = nodeIds.instance(record.featureId);\n const feature = this.sources.plan.features[featureIndex]!;\n\n this.addEdge(edges, 'owns', record.group ?? this.sources.applicationId, consumer);\n\n for (const binding of feature.imports) {\n this.addImportEdge(edges, binding, consumer);\n }\n\n for (const requirement of feature.requirements) {\n this.addRequirementEdge(edges, requirement, consumer);\n }\n\n for (const contribution of this.contributionsByFeature.get(featureIndex) ?? []) {\n this.addContributionEdges(edges, contribution, consumer);\n }\n }\n\n /** T13: one IR requirement edge, three protocol edges — hard, weak with a provider, and weak without one. */\n private addRequirementEdge(\n edges: Map<DiagnosticEdgeId, DiagnosticEdge>,\n requirement: CompiledApplicationPlanIR['requirements'][number],\n consumer: DiagnosticNodeId,\n ): void {\n const port = nodeIds.port(requirement.portId);\n\n if (requirement.provider === undefined) {\n this.addWeakEdge(edges, 'absent-port', port, consumer, 'missing');\n\n return;\n }\n\n if (requirement.optional) {\n this.addWeakEdge(edges, 'optional-port', port, consumer, this.lookupOfFeature(requirement.provider.featureIndex));\n\n return;\n }\n\n this.addHardEdge(edges, 'requires-port', port, consumer, !this.isReady(requirement.provider.featureIndex));\n }\n\n private addWeakEdge(\n edges: Map<DiagnosticEdgeId, DiagnosticEdge>,\n kind: 'absent-import' | 'absent-port' | 'optional-import' | 'optional-port',\n from: DiagnosticNodeId,\n to: DiagnosticNodeId,\n lookup: WeakEdgeState,\n ): void {\n const id = diagnosticEdgeId(kind, from, to);\n edges.set(id, { from, id, kind, lookup, to });\n }\n\n private buildEdges(): ReadonlyMap<DiagnosticEdgeId, DiagnosticEdge> {\n const edges = new Map<DiagnosticEdgeId, DiagnosticEdge>();\n\n for (const [featureIndex, record] of this.instances) this.addInstanceEdges(edges, featureIndex, record);\n\n return edges;\n }\n\n private buildNodes(): ReadonlyMap<DiagnosticNodeId, DiagnosticRuntimeNode> {\n const nodes = new Map<DiagnosticNodeId, DiagnosticRuntimeNode>();\n\n for (const node of this.conditionNodes()) nodes.set(node.id, node);\n\n for (const node of this.groupNodes()) nodes.set(node.id, node);\n\n for (const node of this.instanceNodes()) nodes.set(node.id, node);\n\n for (const node of this.contributionNodes()) nodes.set(node.id, node);\n\n for (const node of this.portNodes()) nodes.set(node.id, node);\n\n for (const node of this.hostContractNodes()) nodes.set(node.id, node);\n\n return nodes;\n }\n\n private conditionHolds(condition: Condition): boolean {\n const readable = this.sources.conditionReadables.get(condition);\n\n return readable !== undefined && this.conditionState(condition, readable).kind === 'true';\n }\n\n private conditionNodes(): readonly ConditionRuntimeNode[] {\n const nodes: ConditionRuntimeNode[] = [];\n\n for (const [condition, readable] of this.sources.conditionReadables) {\n nodes.push({\n declaration: nodeIds.condition(condition.id),\n id: nodeIds.condition(condition.id),\n kind: 'condition',\n label: condition.id,\n state: this.conditionState(condition, readable),\n });\n }\n\n return nodes;\n }\n\n /**\n * D93: a condition computed from a feature reads `false` while that feature has no ready instance, and the panel\n * shows that as `source-closed`. The declaration itself is a frozen `{ id }`, so `from` is resolved through the\n * Record the runtime keeps, not off the condition object.\n */\n /** The product truth of one condition, read past the debug override the control port may have set (D176). */\n private conditionSourceHolds(condition: Condition): boolean {\n const control = this.sources.conditionControls.get(condition.id);\n\n if (control !== undefined) return control.source();\n\n return this.conditionHolds(condition);\n }\n\n private conditionState(condition: Condition, readable: Readable<boolean>): ConditionRuntimeNode['state'] {\n const source = requireConditionRecord(condition).from;\n const sourceIndex =\n source === undefined ? -1 : this.sources.plan.features.findIndex(feature => feature.definition === source);\n\n if (sourceIndex >= 0 && this.instances.get(sourceIndex)?.state.kind !== 'ready') return { kind: 'source-closed' };\n\n return readable.getSnapshot() ? { kind: 'true' } : { kind: 'false' };\n }\n\n private contributionNodes(): readonly ContributionRuntimeNode[] {\n const nodes: ContributionRuntimeNode[] = [];\n\n for (const contribution of this.sources.plan.contributions) {\n const record = this.instances.get(contribution.contributorFeatureIndex);\n\n if (record === undefined) continue;\n\n nodes.push({\n contributor: nodeIds.instance(record.featureId),\n declaration: nodeIds.contribution(contribution.contributionId),\n id: nodeIds.contribution(contribution.contributionId),\n kind: 'contribution',\n label: contribution.contributionId,\n state: this.contributionState(record, contribution.target, contribution.contributionId),\n target: nodeIds.target(contribution.targetId),\n });\n }\n\n return nodes;\n }\n\n /**\n * D79: a contribution whose `when` reads `false` stays published and valid while the target omits it from\n * `entries`, so \"published but invisible\" is read off the target rather than guessed.\n */\n private contributionState(\n record: InstanceRecord,\n target: { readonly entries: Readable<readonly { readonly id: string }[]> },\n contributionId: string,\n ): ContributionState {\n if (record.state.kind === 'opening') return { kind: 'pending' };\n\n if (record.state.kind !== 'ready') return { kind: 'withdrawn' };\n\n const listed = target.entries.getSnapshot().some(entry => entry.id === contributionId);\n\n return listed ? { kind: 'published' } : { kind: 'withheld' };\n }\n\n private diffEdges(desired: ReadonlyMap<DiagnosticEdgeId, DiagnosticEdge>): readonly DiagnosticOperation[] {\n const operations: DiagnosticOperation[] = [];\n\n for (const id of [...this.edges.keys()]) {\n if (desired.has(id)) continue;\n\n this.edges.delete(id);\n operations.push({ id, op: 'remove-edge' });\n }\n\n for (const [id, edge] of desired) {\n if (sameRecord(this.edges.get(id), edge)) continue;\n\n const published = Object.freeze(edge);\n this.edges.set(id, published);\n operations.push({ edge: published, op: 'upsert-edge' });\n }\n\n return operations;\n }\n\n private diffNodes(desired: ReadonlyMap<DiagnosticNodeId, DiagnosticRuntimeNode>): readonly DiagnosticOperation[] {\n const operations: DiagnosticOperation[] = [];\n\n for (const id of [...this.nodes.keys()]) {\n if (desired.has(id)) continue;\n\n this.nodes.delete(id);\n operations.push({ id, op: 'remove-node' });\n }\n\n for (const [id, node] of desired) {\n if (sameRecord(this.nodes.get(id), node)) continue;\n\n const published = Object.freeze(node);\n this.nodes.set(id, published);\n operations.push({ node: published, op: 'upsert-node' });\n }\n\n return operations;\n }\n\n private groupNodes(): readonly ConditionGroupRuntimeNode[] {\n return this.sources.plan.groups.map(group => {\n const effective: DesiredAxis = group.conditions.every(condition => this.conditionHolds(condition))\n ? 'active'\n : 'inactive';\n // D176: `source` is what the product says and `effective` is what the runtime acts on; the override names why.\n const overridden = group.conditions.some(\n condition => this.sources.conditionControls.get(condition.id)?.overridden() === true,\n );\n const source: DesiredAxis = group.conditions.every(condition => this.conditionSourceHolds(condition))\n ? 'active'\n : 'inactive';\n\n return withCause(\n {\n declaration: nodeIds.group(group.groupId),\n desired: { effective, override: overridden ? ('force-inactive' as const) : ('none' as const), source },\n id: nodeIds.group(group.groupId),\n kind: 'condition-group' as const,\n label: `when ${group.conditions.map(condition => condition.id as string).join(' & ')}`,\n state: this.groupStates.get(group.groupId) ?? ({ kind: 'inactive', reason: 'condition-inactive' } as const),\n },\n this.groupCauses.get(group.groupId),\n );\n });\n }\n\n private hostContractNodes(): readonly HostContractRuntimeNode[] {\n const nodes = new Map<string, HostContractRuntimeNode>();\n\n for (const binding of this.sources.plan.imports) {\n if (binding.provider.kind !== 'application-input' || nodes.has(binding.contractId)) continue;\n\n nodes.set(binding.contractId, {\n declaration: nodeIds.hostContract(binding.contractId),\n id: nodeIds.hostContract(binding.contractId),\n kind: 'host-contract',\n label: binding.contractId,\n state: this.hostContractState(binding.contract, binding.demand),\n });\n }\n\n return [...nodes.values()];\n }\n\n private hostContractState(contract: object, demand: 'instance' | 'onDemand'): HostContractState {\n if (demand === 'onDemand') return { kind: 'deferred' };\n\n return this.sources.boundContracts.has(contract) ? { kind: 'bound' } : { kind: 'unbound' };\n }\n\n private instanceNodes(): readonly FeatureInstanceNode[] {\n const nodes: FeatureInstanceNode[] = [];\n\n for (const record of this.instances.values()) {\n nodes.push(\n withCause(\n {\n declaration: nodeIds.feature(record.featureId),\n generation: record.generation,\n ...(record.group === undefined ? {} : { group: record.group }),\n id: nodeIds.instance(record.featureId),\n kind: 'feature-instance' as const,\n label: record.featureId,\n ...(record.previous === undefined ? {} : { previous: record.previous }),\n state: record.state,\n },\n record.cause,\n ),\n );\n }\n\n return nodes;\n }\n\n private isReady(featureIndex: number): boolean {\n return this.instances.get(featureIndex)?.state.kind === 'ready';\n }\n\n private lookupOfFeature(featureIndex: number): WeakEdgeState {\n return this.isReady(featureIndex) ? 'found' : 'missing';\n }\n\n private portNodes(): readonly PortRuntimeNode[] {\n const nodes = new Map<string, PortRuntimeNode>();\n\n for (const requirement of this.sources.plan.requirements) {\n if (nodes.has(requirement.portId)) continue;\n\n nodes.set(requirement.portId, {\n declaration: nodeIds.port(requirement.portId),\n id: nodeIds.port(requirement.portId),\n kind: 'port',\n label: requirement.portId,\n state: this.portState(requirement.provider?.featureIndex),\n });\n }\n\n for (const provider of this.sources.plan.providers) {\n if (nodes.has(provider.portId)) continue;\n\n nodes.set(provider.portId, {\n declaration: nodeIds.port(provider.portId),\n id: nodeIds.port(provider.portId),\n kind: 'port',\n label: provider.portId,\n state: this.portState(provider.featureIndex),\n });\n }\n\n return [...nodes.values()];\n }\n\n /** T8: the provider is chosen at compile time, so the only live question is whether it has a ready instance. */\n private portState(providerIndex: number | undefined): PortState {\n if (providerIndex === undefined) return { kind: 'absent' };\n\n const provider = this.sources.plan.features[providerIndex];\n const record = this.instances.get(providerIndex);\n\n if (record?.state.kind === 'ready') return { instance: nodeIds.instance(record.featureId), kind: 'available' };\n\n return { kind: 'unavailable', provider: nodeIds.feature(provider?.featureId ?? String(providerIndex)) };\n }\n\n private providerNodeId(featureIndex: number): DiagnosticNodeId {\n const record = this.instances.get(featureIndex);\n\n if (record !== undefined) return nodeIds.instance(record.featureId);\n\n return nodeIds.feature(this.sources.plan.features[featureIndex]?.featureId ?? String(featureIndex));\n }\n}\n\nexport { InspectionState };\nexport type { InspectionSources };\n"],"names":["withCause","node","cause","InspectionState","sources","entry","entries","featureIndex","record","feature","previous","_a","nodeIds","nodes","edges","groupId","state","snapshotRuntimeState","contribution","consumer","kind","from","to","id","diagnosticEdgeId","pending","binding","provider","found","requirement","port","lookup","condition","readable","control","source","requireConditionRecord","sourceIndex","target","contributionId","desired","operations","edge","sameRecord","published","group","effective","overridden","contract","demand","providerIndex"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { FeatureInstance } from './module-generation.js';
2
+ type InstanceDemandHandle<Ready> = Pick<FeatureInstance<string, Ready>, 'close' | 'ready'>;
3
+ interface InstanceDemandState<Ready> {
4
+ readonly error: unknown | null;
5
+ readonly instance: Ready | null;
6
+ }
7
+ interface InstanceDemandStatePort<Ready> {
8
+ getState(): InstanceDemandState<Ready>;
9
+ publish(patch: Partial<InstanceDemandState<Ready>>): void;
10
+ }
11
+ interface InstanceDemandLease {
12
+ readonly release: () => Promise<void>;
13
+ readonly settled: Promise<void>;
14
+ }
15
+ interface InstanceDemandCoordinator {
16
+ acquire(): InstanceDemandLease;
17
+ setGateOpen(value: boolean): Promise<void>;
18
+ }
19
+ interface InstanceDemandOptions<Ready> {
20
+ readonly open: (signal: AbortSignal) => Promise<InstanceDemandHandle<Ready>>;
21
+ readonly state: InstanceDemandStatePort<Ready>;
22
+ }
23
+ type CleanupRetryError = {
24
+ readonly code: 'quarantined';
25
+ readonly name: 'FeatureError';
26
+ retryCleanup(): Promise<void>;
27
+ };
28
+ declare function isCleanupRetryError(error: unknown): error is CleanupRetryError;
29
+ declare function createInstanceDemandCoordinator<Ready>(options: InstanceDemandOptions<Ready>): InstanceDemandCoordinator;
30
+ export { createInstanceDemandCoordinator, isCleanupRetryError };
31
+ export type { CleanupRetryError, InstanceDemandCoordinator, InstanceDemandHandle, InstanceDemandLease, InstanceDemandOptions, InstanceDemandState, InstanceDemandStatePort, };
@@ -0,0 +1,2 @@
1
+ const o=Symbol("opetope.instance-demand.cleanup-complete");function s(r){if(typeof r!="object"||r===null)return!1;const e=r;return e.name==="FeatureError"&&e.code==="quarantined"&&typeof e.retryCleanup=="function"}class a{options;cleanup;cleanupError;demands=0;epoch=0;gateOpen=!1;instance;opening;openingAbort;openingEpoch;recovery;constructor(e){this.options=e}acquire(){this.demands+=1;const e=this.ensureDesired(!0);let n;return Object.freeze({release:()=>n??(n=Promise.resolve().then(()=>{if(this.demands-=1,this.demands===0)return this.invalidateAndRetire()})),settled:e})}setGateOpen(e){return this.gateOpen=e,e?this.ensureDesired(!0):this.invalidateAndRetire()}clearOpeningError(){this.cleanupError===void 0&&this.options.state.getState().error!==null&&this.options.state.publish({error:null})}desired(e){return this.gateOpen&&this.demands>0&&e===this.epoch}ensureDesired(e){if(!this.gateOpen||this.demands===0||this.options.state.getState().instance!==null)return Promise.resolve();if(this.cleanupError!==void 0)return e?this.recoverCleanup():Promise.reject(this.cleanupError);if(this.cleanup!==void 0)return this.cleanup.then(()=>this.ensureDesired(e));if(this.opening!==void 0)return this.openingEpoch===this.epoch?this.opening:this.opening.then(()=>this.ensureDesired(e),()=>this.ensureDesired(e));const n=this.epoch,t=new AbortController,i=Promise.resolve().then(()=>this.openGeneration(n,t.signal)).finally(()=>{this.opening===i&&(this.opening=void 0,this.openingAbort=void 0,this.openingEpoch=void 0)});return this.opening=i,this.openingAbort=t,this.openingEpoch=n,this.clearOpeningError(),i}invalidateAndRetire(){var n;this.epoch+=1,(n=this.openingAbort)==null||n.abort();const e=this.retireUndesired();return this.clearOpeningError(),e}async openGeneration(e,n){let t;try{t=await this.options.open(n)}catch(i){if(!this.recordOpeningFailure(i,e))return;throw i}if(this.instance=t,t.ready.catch(()=>{}),!this.desired(e))return await this.retireGeneration(t);try{const i=await t.ready;if(!this.desired(e))return await this.retireGeneration(t);this.options.state.publish({error:null,instance:i})}catch(i){if(await this.retireGeneration(t),!this.desired(e))return;throw this.options.state.publish({error:i,instance:null}),i}}projectCleanup(e){return e.then(n=>{if(n!==o)throw n})}recordOpeningFailure(e,n){return s(e)?(this.cleanupError=e,this.options.state.publish({error:e,instance:null}),!0):this.desired(n)?(this.options.state.publish({error:e,instance:null}),!0):!1}recoverCleanup(){const e=this.cleanupError;if(e===void 0)return this.ensureDesired(!1);if(this.recovery!==void 0)return this.recovery.then(()=>this.ensureDesired(!1));const n=Promise.resolve().then(()=>e.retryCleanup()).then(()=>{this.cleanupError===e&&(this.cleanupError=void 0),this.cleanup=void 0,this.recovery=void 0,this.options.state.publish({error:null})},t=>{throw s(t)&&(this.cleanupError=t,this.recovery=void 0),this.options.state.publish({error:t,instance:null}),t});return this.recovery=n,n.then(()=>this.ensureDesired(!1))}retireGeneration(e){if(this.cleanup!==void 0)return this.projectCleanup(this.cleanup);this.instance===e&&(this.instance=void 0);const n=Promise.resolve().then(()=>e.close()).then(()=>(this.cleanup===n&&(this.cleanup=void 0),o),t=>(s(t)?this.cleanupError=t:this.cleanup===n&&(this.cleanup=void 0),this.options.state.publish({error:t,instance:null}),t));return this.cleanup=n,this.options.state.publish({instance:null}),this.projectCleanup(n)}retireUndesired(){if(this.gateOpen&&this.demands>0)return this.ensureDesired(!1);const e=this.instance,n=e===void 0?this.cleanup===void 0?void 0:this.projectCleanup(this.cleanup):this.retireGeneration(e);return Promise.all([n,this.opening]).then(()=>{})}}function h(r){return new a(r)}export{h as createInstanceDemandCoordinator,s as isCleanupRetryError};
2
+ //# sourceMappingURL=instance-demand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance-demand.js","sources":["../src/instance-demand.ts"],"sourcesContent":["import type { FeatureInstance } from './module-generation';\n\ntype InstanceDemandHandle<Ready> = Pick<FeatureInstance<string, Ready>, 'close' | 'ready'>;\n\ninterface InstanceDemandState<Ready> {\n readonly error: unknown | null;\n readonly instance: Ready | null;\n}\n\ninterface InstanceDemandStatePort<Ready> {\n getState(): InstanceDemandState<Ready>;\n publish(patch: Partial<InstanceDemandState<Ready>>): void;\n}\n\ninterface InstanceDemandLease {\n readonly release: () => Promise<void>;\n readonly settled: Promise<void>;\n}\n\ninterface InstanceDemandCoordinator {\n acquire(): InstanceDemandLease;\n setGateOpen(value: boolean): Promise<void>;\n}\n\ninterface InstanceDemandOptions<Ready> {\n readonly open: (signal: AbortSignal) => Promise<InstanceDemandHandle<Ready>>;\n readonly state: InstanceDemandStatePort<Ready>;\n}\n\ntype CleanupRetryError = { readonly code: 'quarantined'; readonly name: 'FeatureError'; retryCleanup(): Promise<void> };\n\nconst cleanupComplete = Symbol('opetope.instance-demand.cleanup-complete');\n\nfunction isCleanupRetryError(error: unknown): error is CleanupRetryError {\n if (typeof error !== 'object' || error === null) return false;\n\n const candidate = error as { readonly code?: unknown; readonly name?: unknown; readonly retryCleanup?: unknown };\n\n return (\n candidate.name === 'FeatureError' &&\n candidate.code === 'quarantined' &&\n typeof candidate.retryCleanup === 'function'\n );\n}\n\nclass Coordinator<Ready> implements InstanceDemandCoordinator {\n private cleanup: Promise<unknown> | undefined;\n private cleanupError: CleanupRetryError | undefined;\n private demands = 0;\n private epoch = 0;\n private gateOpen = false;\n private instance: InstanceDemandHandle<Ready> | undefined;\n private opening: Promise<void> | undefined;\n private openingAbort: AbortController | undefined;\n private openingEpoch: number | undefined;\n private recovery: Promise<void> | undefined;\n\n constructor(private readonly options: InstanceDemandOptions<Ready>) {}\n\n acquire(): InstanceDemandLease {\n this.demands += 1;\n const settled = this.ensureDesired(true);\n let release: Promise<void> | undefined;\n\n return Object.freeze({\n release: () =>\n (release ??= Promise.resolve().then(() => {\n this.demands -= 1;\n\n if (this.demands !== 0) return;\n\n return this.invalidateAndRetire();\n })),\n settled,\n });\n }\n\n setGateOpen(value: boolean): Promise<void> {\n this.gateOpen = value;\n\n if (value) return this.ensureDesired(true);\n\n return this.invalidateAndRetire();\n }\n\n private clearOpeningError(): void {\n if (this.cleanupError === undefined && this.options.state.getState().error !== null) {\n this.options.state.publish({ error: null });\n }\n }\n\n private desired(epoch: number): boolean {\n return this.gateOpen && this.demands > 0 && epoch === this.epoch;\n }\n\n // eslint-disable-next-line complexity -- lifecycle guards are the executable state-machine transition table\n private ensureDesired(recover: boolean): Promise<void> {\n if (!this.gateOpen || this.demands === 0 || this.options.state.getState().instance !== null) {\n return Promise.resolve();\n }\n\n if (this.cleanupError !== undefined) return recover ? this.recoverCleanup() : Promise.reject(this.cleanupError);\n\n if (this.cleanup !== undefined) return this.cleanup.then(() => this.ensureDesired(recover));\n\n if (this.opening !== undefined) {\n if (this.openingEpoch === this.epoch) return this.opening;\n\n return this.opening.then(\n () => this.ensureDesired(recover),\n () => this.ensureDesired(recover),\n );\n }\n\n const epoch = this.epoch;\n const abort = new AbortController();\n const opening = Promise.resolve()\n .then(() => this.openGeneration(epoch, abort.signal))\n .finally(() => {\n if (this.opening === opening) {\n this.opening = undefined;\n this.openingAbort = undefined;\n this.openingEpoch = undefined;\n }\n });\n this.opening = opening;\n this.openingAbort = abort;\n this.openingEpoch = epoch;\n this.clearOpeningError();\n\n return opening;\n }\n\n private invalidateAndRetire(): Promise<void> {\n this.epoch += 1;\n this.openingAbort?.abort();\n\n const retirement = this.retireUndesired();\n\n this.clearOpeningError();\n\n return retirement;\n }\n\n private async openGeneration(epoch: number, signal: AbortSignal): Promise<void> {\n let instance: InstanceDemandHandle<Ready>;\n\n try {\n instance = await this.options.open(signal);\n } catch (error) {\n if (!this.recordOpeningFailure(error, epoch)) return;\n\n throw error;\n }\n this.instance = instance;\n // Retirement may win before the awaited branch below, so observe ready before publishing the handle internally.\n void instance.ready.catch(() => undefined);\n\n if (!this.desired(epoch)) return await this.retireGeneration(instance);\n\n try {\n const ready = await instance.ready;\n\n if (!this.desired(epoch)) return await this.retireGeneration(instance);\n\n this.options.state.publish({ error: null, instance: ready });\n } catch (error) {\n await this.retireGeneration(instance);\n\n if (!this.desired(epoch)) return;\n\n this.options.state.publish({ error, instance: null });\n throw error;\n }\n }\n\n private projectCleanup(cleanup: Promise<unknown>): Promise<void> {\n return cleanup.then(result => {\n if (result !== cleanupComplete) throw result;\n });\n }\n\n private recordOpeningFailure(error: unknown, epoch: number): boolean {\n if (isCleanupRetryError(error)) {\n this.cleanupError = error;\n this.options.state.publish({ error, instance: null });\n\n return true;\n }\n\n if (!this.desired(epoch)) return false;\n\n this.options.state.publish({ error, instance: null });\n\n return true;\n }\n\n private recoverCleanup(): Promise<void> {\n const error = this.cleanupError;\n\n if (error === undefined) return this.ensureDesired(false);\n\n if (this.recovery !== undefined) return this.recovery.then(() => this.ensureDesired(false));\n\n const recovery = Promise.resolve()\n .then(() => error.retryCleanup())\n .then(\n () => {\n if (this.cleanupError === error) this.cleanupError = undefined;\n\n this.cleanup = undefined;\n this.recovery = undefined;\n this.options.state.publish({ error: null });\n },\n (nextError: unknown) => {\n if (isCleanupRetryError(nextError)) {\n this.cleanupError = nextError;\n this.recovery = undefined;\n }\n\n this.options.state.publish({ error: nextError, instance: null });\n throw nextError;\n },\n );\n this.recovery = recovery;\n\n return recovery.then(() => this.ensureDesired(false));\n }\n\n private retireGeneration(instance: InstanceDemandHandle<Ready>): Promise<void> {\n if (this.cleanup !== undefined) return this.projectCleanup(this.cleanup);\n\n if (this.instance === instance) this.instance = undefined;\n\n const cleanup = Promise.resolve()\n .then(() => instance.close())\n .then(\n () => {\n if (this.cleanup === cleanup) this.cleanup = undefined;\n\n return cleanupComplete;\n },\n (error: unknown) => {\n if (isCleanupRetryError(error)) {\n this.cleanupError = error;\n } else if (this.cleanup === cleanup) {\n this.cleanup = undefined;\n }\n\n this.options.state.publish({ error, instance: null });\n\n return error;\n },\n );\n this.cleanup = cleanup;\n this.options.state.publish({ instance: null });\n\n return this.projectCleanup(cleanup);\n }\n\n private retireUndesired(): Promise<void> {\n if (this.gateOpen && this.demands > 0) return this.ensureDesired(false);\n\n const instance = this.instance;\n const retirement =\n instance === undefined\n ? this.cleanup === undefined\n ? undefined\n : this.projectCleanup(this.cleanup)\n : this.retireGeneration(instance);\n\n return Promise.all([retirement, this.opening]).then(() => undefined);\n }\n}\n\nfunction createInstanceDemandCoordinator<Ready>(options: InstanceDemandOptions<Ready>): InstanceDemandCoordinator {\n return new Coordinator(options);\n}\n\nexport { createInstanceDemandCoordinator, isCleanupRetryError };\nexport type {\n CleanupRetryError,\n InstanceDemandCoordinator,\n InstanceDemandHandle,\n InstanceDemandLease,\n InstanceDemandOptions,\n InstanceDemandState,\n InstanceDemandStatePort,\n};\n"],"names":["cleanupComplete","isCleanupRetryError","error","candidate","Coordinator","options","settled","release","value","epoch","recover","abort","opening","_a","retirement","signal","instance","ready","cleanup","result","recovery","nextError","createInstanceDemandCoordinator"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export type { ApplicationCompileInput, ApplicationImportProviderIR, ApplicationLifetimeOwnerIR, ApplicationPortProviderIR, ApplicationTopologyEdgeIR, CompiledApplicationContributionIR, CompiledApplicationFeatureIR, CompiledApplicationImportIR, CompiledApplicationPlanIR, CompiledApplicationRequirementIR, CompiledConditionGroupIR, } from './application-compiler.js';
2
+ export { getApplicationPlan } from './application-definition.js';
3
+ export type { ApplicationConditionId } from './application-definition.js';
4
+ export type { ApplicationExecution, ApplicationImportBinding, OpenApplicationOptions } from './application-execution.js';
5
+ export { createAttachmentCall } from './attachment-call-declaration.js';
6
+ export type { AttachmentCallOptions, AttachmentCallRef } from './attachment-call-declaration.js';
7
+ export { createScopeBlueprint } from './attachment-declaration.js';
8
+ export type { AttachmentCloseContext, AttachmentExecutionContext, AttachmentOpenContext, AttachmentOwnedStep, AttachmentOwner, AttachmentReadinessPolicy, AttachmentStepContext, LifetimeAttachmentOptions, LifetimeAttachmentRef, ScopeBlueprint, } from './attachment-declaration.js';
9
+ export { compileModuleTemplate, createLocalAttachmentModuleDefinition } from './compile-module-template.js';
10
+ export type { LocalAttachmentModuleDefinition, RuntimeBlueprint, RuntimeBlueprintRecord, } from './compile-module-template.js';
11
+ export type { ConditionGroupEntry, ConditionGroupExecution, ConditionGroupExecutionOptions, ConditionSnapshot, GroupMemberInstance, } from './condition-group-execution.js';
12
+ export type { ConditionSource } from './condition-source.js';
13
+ export { createControlSession } from './control-registry.js';
14
+ export type { ControlOutcome, RuntimeControlSession } from './control-registry.js';
15
+ export type { FeatureExportsOf, FeatureIdOf, FeatureImportsOf, FeatureRequirementsOf } from './feature-authoring.js';
16
+ export type { FeatureContract } from './feature-contract.js';
17
+ export type { ImportDemand, OnDemandHostContract, OptionalHostContract } from './feature-contract.js';
18
+ export type { FeatureContributionDescriptor } from './feature-contribution.js';
19
+ export { openContributionModels, requireContributionModelPlans } from './feature-contribution-model.js';
20
+ export type { ContributionModel, ContributionModelBundle, ContributionModelPlan } from './feature-contribution-model.js';
21
+ export type { FeatureReady, FeatureReadyOf } from './feature-generation.js';
22
+ export { bindFeatureResource } from './feature-materialization-binding.js';
23
+ export type { FeatureResourceRef, FeatureStreamRef } from './feature-materialization-types.js';
24
+ export type { FeatureModelRef } from './feature-model.js';
25
+ export type { ActivityOwner, CallActivity, FeatureActivity, ResourceActivity, ResourceLoadActivity, RuntimeActivitySnapshot, } from './inspection-activity-protocol.js';
26
+ export type { ApplicationPlanSnapshot, ConditionGroupState, ContributionState, DiagnosticEdge, DiagnosticOperation, FeatureInstanceState, HostContractState, PortState, ReadLimits, ReadResult, RuntimeGraphFrame, RuntimeGraphSnapshot, RuntimeInspectionSession, RuntimeStateSnapshot, } from './inspection-protocol.js';
27
+ export { createInspectionSession } from './inspection-registry.js';
28
+ export { createInstanceDemandCoordinator } from './instance-demand.js';
29
+ export type { InstanceDemandCoordinator, InstanceDemandHandle, InstanceDemandLease, InstanceDemandOptions, InstanceDemandState, InstanceDemandStatePort, } from './instance-demand.js';
30
+ export { instantiateModuleTemplate } from './module-instance.js';
31
+ export type { LocalAttachmentCloseFailure, LocalAttachmentIdentity, LocalAttachmentModuleDiagnostics, LocalAttachmentModuleInstance, LocalScopeDrainOutcome, LocalScopeInstance, LocalScopeOpenOutcome, LocalScopeRetirement, } from './module-instance.js';
32
+ export type { AttachmentNodeIR, AttachmentTemplateSlot, CallTargetBindingIR, CallTargetBindingSlot, CompiledModuleTemplateIR, RuntimeNodeIdentityIR, ScopeAttachmentSlot, ScopeNodeIR, ScopeTemplateSlot, } from './module-template-ir.js';
33
+ export { acknowledgeOwnerGenerationDrain, bindAttachmentLifecycleToOwner, createOwnerGenerationSlot, openOwnerBoundAttachment, retireOwnedGeneration, retryOwnerBoundAttachmentClose, } from './owner-generation.js';
34
+ export type { OwnerBoundAttachment, OwnerGeneration, OwnerGenerationController, OwnerGenerationRef, OwnerGenerationRetirement, OwnerGenerationSnapshot, } from './owner-generation.js';
35
+ export { resolveModuleCallTarget } from './public-module.js';
36
+ export type { ModuleInstance, ModuleRetirementParticipant, ModuleRetirementParticipantHandle } from './public-module.js';
37
+ export { defineModule, instantiateModule } from './public-module.js';
38
+ export type { ModuleAttachmentCleanupFailureDiagnostic, ModuleAttachmentCloseContext, ModuleAttachmentOpenContext, ModuleAttachmentOptions, ModuleAttachmentRef, ModuleCallContext, ModuleCallRef, ModuleCleanupErrorDiagnostic, ModuleCleanupFailureDiagnostic, ModuleDefinition, ModuleDefinitionOptions, ModuleDrainOutcome, ModuleInstanceOptions, ModuleInstanceRef, ModuleParticipantRetirementFailure, ModuleRetirement, ModuleRetirementFailure, ModuleRetirementQuarantinedOutcome, ModuleRuntimeBuilder, ModuleRuntimeRecord, ModuleRuntimeRef, ModuleScopeDrainOutcome, ModuleScopeInstance, ModuleScopeOpenOutcome, ModuleScopeRef, ModuleScopeRetirement, ModuleScopeRetirementFailure, } from './public-module.js';
39
+ export type { ManagedResourceRef, ResourceControllerOptions, ResourceLoadContext } from './resource-controller.js';
40
+ export type { ResourceRequestKey, ResourceRetry } from './resource-types.js';
41
+ export type { ManagedStreamRef, StreamConnectContext, StreamConsumeContext, StreamControllerOptions, StreamDisposer, } from './stream-controller.js';
@@ -0,0 +1,2 @@
1
+ import{getApplicationPlan as t}from"./application-definition.js";import{createAttachmentCall as n}from"./attachment-call-declaration.js";import{createScopeBlueprint as i}from"./attachment-declaration.js";import{compileModuleTemplate as p,createLocalAttachmentModuleDefinition as m}from"./compile-module-template.js";import{createControlSession as d}from"./control-registry.js";import{openContributionModels as u,requireContributionModelPlans as x}from"./feature-contribution-model.js";import{bindFeatureResource as M}from"./feature-materialization-binding.js";import{createInspectionSession as C}from"./inspection-registry.js";import{createInstanceDemandCoordinator as O}from"./instance-demand.js";import{instantiateModuleTemplate as b}from"./module-instance.js";import{bindAttachmentLifecycleToOwner as T,createOwnerGenerationSlot as g,openOwnerBoundAttachment as B,retryOwnerBoundAttachmentClose as D}from"./owner-generation.js";import{acknowledgeOwnerGenerationDrain as y,retireOwnedGeneration as I}from"./owner-generation-retirement.js";import{defineModule as P}from"./public-module-definition.js";import{instantiateModule as q,resolveModuleCallTarget as v}from"./public-module-instance.js";export{y as acknowledgeOwnerGenerationDrain,T as bindAttachmentLifecycleToOwner,M as bindFeatureResource,p as compileModuleTemplate,n as createAttachmentCall,d as createControlSession,C as createInspectionSession,O as createInstanceDemandCoordinator,m as createLocalAttachmentModuleDefinition,g as createOwnerGenerationSlot,i as createScopeBlueprint,P as defineModule,t as getApplicationPlan,q as instantiateModule,b as instantiateModuleTemplate,u as openContributionModels,B as openOwnerBoundAttachment,x as requireContributionModelPlans,v as resolveModuleCallTarget,I as retireOwnedGeneration,D as retryOwnerBoundAttachmentClose};
2
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ import type { DynamicScopeChild } from './dynamic-scope-child.js';
2
+ import type { FeatureScopeKey } from './feature-scope-types.js';
3
+ import type { ErrorReporter } from './public-module.js';
4
+ interface KeyedScopeController<Value> {
5
+ readonly dispose: () => Promise<void>;
6
+ readonly fence: () => void;
7
+ readonly invalidateProjection: () => void;
8
+ readonly update: (values: readonly Value[]) => Promise<void>;
9
+ }
10
+ declare function createKeyedScopeController<Value>(child: DynamicScopeChild<Value>, selectKey: (value: Value) => FeatureScopeKey, reporter: ErrorReporter | undefined): KeyedScopeController<Value>;
11
+ export { createKeyedScopeController };
@@ -0,0 +1,2 @@
1
+ import{closedSelection as O,dynamicScopeSelection as f,createDynamicScopeController as y}from"./dynamic-scope-controller.js";function P(l){if(!Array.isArray(l))throw new TypeError("Feature keyed scope source must contain a readonly array.")}function b(l,p,a,n){P(l);const i=new Map;for(const c of l){if(!n(a))return;const s=p(c);if(!n(a))return;if(typeof s!="string"&&typeof s!="number")throw new TypeError("Feature keyed scope key must be a string or number.");if(i.has(s))throw new TypeError(`Feature keyed scope contains duplicate key ${String(s)}.`);i.set(s,c)}return i}function S(l,p,a){const n=new Map;let i=!1,c,s=0;const u=t=>!i&&s===t,m=(t,e)=>{const r={controller:y(l,a),disposing:!1,latest:e,present:!0,replacementOperation:void 0,revision:1};return n.set(t,r),r},w=async(t,e)=>{if(e.replacementOperation!==void 0)return e.replacementOperation;const r=(async()=>{if(await e.controller.dispose(),i||!e.present||n.get(t)!==e){n.get(t)===e&&n.delete(t);return}const o=m(t,e.latest);await o.controller.update(f(o.latest,t))})();return e.replacementOperation=r,r.catch(()=>{e.replacementOperation===r&&(e.replacementOperation=void 0)}),r},g=(t,e)=>{const r=n.get(t);return r===void 0?m(t,e).controller.update(f(e,t)):(r.latest=e,r.present=!0,r.revision+=1,r.disposing?w(t,r):r.controller.update(f(e,t)))},v=(t,e)=>{e.present=!1,e.revision+=1;const r=e.revision;return(async()=>{await e.controller.update(O),!(i||e.present||e.revision!==r||n.get(t)!==e)&&(e.disposing=!0,await e.controller.dispose(),n.get(t)===e&&!e.present&&n.delete(t))})()},h=()=>{if(!i){i=!0;for(const t of n.values())t.controller.fence()}},E=(t,e)=>{const r=[];for(const[o,d]of n){if(!u(e))break;!t.has(o)&&d.present&&r.push(v(o,d))}for(const[o,d]of t){if(!u(e))break;r.push(g(o,d))}return Promise.all(r).then(()=>{})};return Object.freeze({dispose(){if(c!==void 0)return c;h();const t=(async()=>{const e=[];if(await Promise.all([...n].map(async([r,o])=>{try{await o.controller.dispose(),n.get(r)===o&&n.delete(r)}catch(d){e.push(d)}})),e.length!==0){for(const r of e.slice(1))try{const o=a==null?void 0:a(r);o!==void 0&&Promise.resolve(o).catch(()=>{})}catch{}throw e[0]}})();return c=t,t.catch(()=>{c===t&&(c=void 0)}),t},fence:h,invalidateProjection(){s+=1},update(t){if(i)return Promise.reject(new TypeError("Keyed scope controller is retired."));const e=++s;let r;try{r=b(t,p,e,u)}catch(o){return Promise.reject(o)}return r===void 0||!u(e)?Promise.resolve():E(r,e)}})}export{S as createKeyedScopeController};
2
+ //# sourceMappingURL=keyed-scope-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyed-scope-controller.js","sources":["../src/keyed-scope-controller.ts"],"sourcesContent":["import type { DynamicScopeChild } from './dynamic-scope-child';\nimport { closedSelection, createDynamicScopeController, dynamicScopeSelection } from './dynamic-scope-controller';\nimport type { DynamicScopeController } from './dynamic-scope-controller';\nimport type { FeatureScopeKey } from './feature-scope-types';\nimport type { ErrorReporter } from './public-module';\n\ntype KeyedScopeEntry<Value> = {\n controller: DynamicScopeController<Value>;\n disposing: boolean;\n latest: Value;\n present: boolean;\n replacementOperation: Promise<void> | undefined;\n revision: number;\n};\n\ninterface KeyedScopeController<Value> {\n readonly dispose: () => Promise<void>;\n readonly fence: () => void;\n readonly invalidateProjection: () => void;\n readonly update: (values: readonly Value[]) => Promise<void>;\n}\n\nfunction assertKeyedValues(value: unknown): void {\n if (!Array.isArray(value)) throw new TypeError('Feature keyed scope source must contain a readonly array.');\n}\n\nfunction collectKeyedValues<Value>(\n values: readonly Value[],\n selectKey: (value: Value) => FeatureScopeKey,\n revision: number,\n isCurrent: (revision: number) => boolean,\n): ReadonlyMap<FeatureScopeKey, Value> | undefined {\n assertKeyedValues(values);\n\n const selected = new Map<FeatureScopeKey, Value>();\n\n for (const value of values) {\n if (!isCurrent(revision)) return undefined;\n\n const key = selectKey(value);\n\n if (!isCurrent(revision)) return undefined;\n\n if (typeof key !== 'string' && typeof key !== 'number') {\n throw new TypeError('Feature keyed scope key must be a string or number.');\n }\n\n if (selected.has(key)) throw new TypeError(`Feature keyed scope contains duplicate key ${String(key)}.`);\n\n selected.set(key, value);\n }\n\n return selected;\n}\n\nfunction createKeyedScopeController<Value>(\n child: DynamicScopeChild<Value>,\n selectKey: (value: Value) => FeatureScopeKey,\n reporter: ErrorReporter | undefined,\n): KeyedScopeController<Value> {\n const entries = new Map<FeatureScopeKey, KeyedScopeEntry<Value>>();\n let disposed = false;\n let disposeOperation: Promise<void> | undefined;\n let updateRevision = 0;\n const isCurrentUpdate = (revision: number): boolean => !disposed && updateRevision === revision;\n\n const createEntry = (key: FeatureScopeKey, value: Value): KeyedScopeEntry<Value> => {\n const entry: KeyedScopeEntry<Value> = {\n controller: createDynamicScopeController(child, reporter),\n disposing: false,\n latest: value,\n present: true,\n replacementOperation: undefined,\n revision: 1,\n };\n entries.set(key, entry);\n\n return entry;\n };\n const replaceDisposedEntry = async (key: FeatureScopeKey, entry: KeyedScopeEntry<Value>): Promise<void> => {\n if (entry.replacementOperation !== undefined) return entry.replacementOperation;\n\n const replacementOperation = (async () => {\n await entry.controller.dispose();\n\n if (disposed || !entry.present || entries.get(key) !== entry) {\n if (entries.get(key) === entry) entries.delete(key);\n\n return;\n }\n\n const replacement = createEntry(key, entry.latest);\n await replacement.controller.update(dynamicScopeSelection(replacement.latest, key));\n })();\n entry.replacementOperation = replacementOperation;\n void replacementOperation.catch(() => {\n if (entry.replacementOperation === replacementOperation) entry.replacementOperation = undefined;\n });\n\n return replacementOperation;\n };\n const openEntry = (key: FeatureScopeKey, value: Value): Promise<void> => {\n const existing = entries.get(key);\n\n if (existing === undefined) {\n const created = createEntry(key, value);\n\n return created.controller.update(dynamicScopeSelection(value, key));\n }\n\n existing.latest = value;\n existing.present = true;\n existing.revision += 1;\n\n return existing.disposing\n ? replaceDisposedEntry(key, existing)\n : existing.controller.update(dynamicScopeSelection(value, key));\n };\n const closeEntry = (key: FeatureScopeKey, entry: KeyedScopeEntry<Value>): Promise<void> => {\n entry.present = false;\n entry.revision += 1;\n const revision = entry.revision;\n\n return (async () => {\n await entry.controller.update(closedSelection);\n\n if (disposed || entry.present || entry.revision !== revision || entries.get(key) !== entry) return;\n\n entry.disposing = true;\n await entry.controller.dispose();\n\n if (entries.get(key) === entry && !entry.present) entries.delete(key);\n })();\n };\n const fence = (): void => {\n if (disposed) return;\n\n disposed = true;\n\n for (const entry of entries.values()) entry.controller.fence();\n };\n const reconcileEntries = (selected: ReadonlyMap<FeatureScopeKey, Value>, revision: number): Promise<void> => {\n const operations: Promise<void>[] = [];\n\n for (const [key, entry] of entries) {\n if (!isCurrentUpdate(revision)) break;\n\n if (!selected.has(key) && entry.present) operations.push(closeEntry(key, entry));\n }\n\n for (const [key, value] of selected) {\n if (!isCurrentUpdate(revision)) break;\n\n operations.push(openEntry(key, value));\n }\n\n return Promise.all(operations).then(() => undefined);\n };\n\n return Object.freeze({\n dispose(): Promise<void> {\n if (disposeOperation !== undefined) return disposeOperation;\n\n fence();\n const operation = (async () => {\n const failures: unknown[] = [];\n\n await Promise.all(\n [...entries].map(async ([key, entry]) => {\n try {\n await entry.controller.dispose();\n\n if (entries.get(key) === entry) entries.delete(key);\n } catch (error) {\n failures.push(error);\n }\n }),\n );\n\n if (failures.length === 0) return;\n\n for (const failure of failures.slice(1)) {\n try {\n const result = reporter?.(failure);\n\n if (result !== undefined) void Promise.resolve(result).catch(() => undefined);\n } catch {\n // The first cleanup failure remains the deterministic retirement result.\n }\n }\n\n throw failures[0];\n })();\n disposeOperation = operation;\n void operation.catch(() => {\n if (disposeOperation === operation) disposeOperation = undefined;\n });\n\n return operation;\n },\n fence,\n invalidateProjection(): void {\n updateRevision += 1;\n },\n update(values: readonly Value[]): Promise<void> {\n if (disposed) return Promise.reject(new TypeError('Keyed scope controller is retired.'));\n\n const revision = ++updateRevision;\n let selected: ReadonlyMap<FeatureScopeKey, Value> | undefined;\n\n try {\n selected = collectKeyedValues(values, selectKey, revision, isCurrentUpdate);\n } catch (error) {\n return Promise.reject(error);\n }\n\n if (selected === undefined || !isCurrentUpdate(revision)) return Promise.resolve();\n\n return reconcileEntries(selected, revision);\n },\n });\n}\n\nexport { createKeyedScopeController };\n"],"names":["assertKeyedValues","value","collectKeyedValues","values","selectKey","revision","isCurrent","selected","key","createKeyedScopeController","child","reporter","entries","disposed","disposeOperation","updateRevision","isCurrentUpdate","createEntry","entry","createDynamicScopeController","replaceDisposedEntry","replacementOperation","replacement","dynamicScopeSelection","openEntry","existing","closeEntry","closedSelection","fence","reconcileEntries","operations","operation","failures","error","failure","result"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ModelContext, OwnedState } from '@opetope/core';
2
+ import type { FeatureActivityOwner } from './inspection-activity.js';
3
+ import type { RuntimeErrorReporter } from './runtime-error-reporting.js';
4
+ type ModelStateFactory = <Value>(initial: Value) => OwnedState<Value>;
5
+ type ModelStateWriter = <Value>(state: OwnedState<Value>, value: Value) => void;
6
+ interface ModelKernel {
7
+ readonly context: ModelContext;
8
+ readonly drain: () => Promise<void>;
9
+ readonly fence: () => void;
10
+ readonly ownsCall: (target: object) => boolean;
11
+ }
12
+ /**
13
+ * A model owns its nodes: they are created when the generation opens the model and released in the same drain. The
14
+ * readiness controller is the fence, so a call after retire is a cancellation and never a product failure (D73).
15
+ */
16
+ declare function createModelKernel(id: string, signal: AbortSignal, reporter: RuntimeErrorReporter | undefined, state: ModelStateFactory, update: ModelStateWriter, activity?: FeatureActivityOwner): ModelKernel;
17
+ export { createModelKernel };
18
+ export type { ModelKernel };
@@ -0,0 +1,2 @@
1
+ import{createAttachmentReadinessController as G,defineCallLane as W,createCallExecutor as N,bindCallTargetToAttachment as Q,defineCallTarget as B,assertCallContextCurrent as E,invokeCallTargetWithGuard as D,inheritCallContextLifetime as H,inheritCallExecutionMetadata as J,releaseCallExecutionMetadata as F,retireCallContext as $,settleGuardedResult as U}from"@opetope/core/internal";import{kernelCallScheduling as V,snapshotCallPolicy as X,snapshotCallSingleFlight as Y,snapshotCallOnce as Z}from"./call-option-snapshot.js";import{snapshotCallsKeys as _}from"./feature-calls.js";import{snapshotEffectOptions as ee,openEffect as te}from"./feature-effect.js";import{snapshotEventOptions as ne,createEventQueue as re}from"./feature-event.js";import{selectTargetReadable as P,snapshotFeatureResourceOptions as oe,requireRequestKey as K}from"./feature-resource.js";import{createReactiveScopeNode as le,createReactiveScopeState as se}from"./feature-scope.js";import{snapshotFeatureStreamOptions as ce}from"./feature-stream.js";import{createTimerRegistry as ae}from"./feature-timers.js";import{createResourceController as ie}from"./resource-controller.js";import{reportRuntimeFailure as fe}from"./runtime-error-reporting.js";import{createStreamController as ue}from"./stream-controller.js";const v=new WeakMap,de=new Set(["lane","once","policy","run","singleFlight"]),pe=new Set(["lane","policy"]);function me(r,o){if(typeof r!="function")throw new TypeError(`${o} must be a function.`);return r}function he(r,o){if(r===void 0)return;const l=v.get(r);if(l===void 0)throw new TypeError("Model call lane is not authentic.");if(o==="parallel")throw new TypeError("Parallel model calls cannot declare a lane.");return l}function ye(r){if(typeof r!="object"||r===null)throw new TypeError("Model call options must be a record.");for(const m of Reflect.ownKeys(r))if(!de.has(m))throw new TypeError(`Model call options contain unknown field ${String(m)}.`);const o=r,l=X(o.policy,"Model call");return Object.freeze({lane:he(o.lane,l),once:Z(o.once,"Model call"),policy:l,run:me(o.run,"Model call run"),singleFlight:Y(o.singleFlight,"Model call")})}function we(r){if(r===void 0)return{lane:void 0,policy:void 0};if(typeof r!="object"||r===null)throw new TypeError("Model calls options must be a record.");for(const l of Reflect.ownKeys(r))if(!pe.has(l))throw new TypeError(`Model calls options contain unknown field ${String(l)}.`);const o=r;return{lane:o.lane,policy:o.policy}}function ge(r,o,l){if(typeof r!="object"||r===null)throw new TypeError("Model calls source must be a record.");const m=r,a={};for(const u of _(o,"Model calls")){if(typeof m[u]!="function")throw new TypeError(`Model calls source field ${u} is not a method.`);a[u]=m[u]}const f=we(l);return Object.freeze({lane:f.lane,methods:Object.freeze(a),policy:f.policy,source:r})}function Ce(r,o,l,m){const a=Object.freeze({invoke(y,C){try{return E(a),Promise.resolve(D(y,C,a,()=>E(a)))}catch(w){return Promise.reject(w)}},signal:m.signal,throwIfAborted(){E(a)}}),f=()=>E(a);let u;try{H(l,a),J(a,a),u=r.run(o,a)}catch(y){throw F(a),$(a),y}return U(u,{assertCurrent:f,finalize:()=>{F(a),$(a)},waitForPhysicalSettlement:!0})}function be(r,o,l,m,a,f){const u=G({id:r});u.publishReady(u.beginOpen());const y=ae(o,l),C=[],w=[],k=new WeakSet,R=Object.freeze({});let b,M=!1,S=0;const T=e=>(S+=1,`${r}.${e}.${String(S)}`),O=e=>fe(e,l),p=e=>{if(M)throw new TypeError(`Model ${e} is unavailable after retire.`)},g=(e,n=()=>{})=>{w.push({drain:e,fence:n}),M&&n()},j=(e,n)=>{p(`scope.${e}`);const s=le(e,T(`scope.${e}`),n),t=se(s.from,o,s.createController(l),l);g(t.close,t.fence),t.open().catch(O)},x=(e,n)=>(g(e.close,e.fence),f==null||f.registerResource(n,e),e),q=e=>{x(e,"resource")},I=e=>{x(e,"stream")},z=e=>{p("call");const n=ye(e),s=T("call"),t=N({id:s,...n.once===void 0?{}:{once:n.once},scheduling:V(n.policy,n.lane),...n.singleFlight===void 0?{}:{singleFlight:n.singleFlight}},f);C.push(t),f==null||f.registerCall(t);const d=Q(B({id:s,run:(c,i)=>t.start(c,h=>Ce(n,c,i,h),{generation:R,parent:i,signal:o})}),u.ref);return k.add(d),d},L=Object.freeze({call:z,calls(e,n,s){p("calls");const t=ge(e,n,s),d=Object.entries(t.methods).map(([c,i])=>[c,z({lane:t.lane,policy:t.policy,run:(h,A)=>i.call(t.source,h,A.signal)})]);return Object.freeze(Object.fromEntries(d))},cleanup(e){if(typeof e!="function")throw new TypeError("Model cleanup expects a disposer function.");p("cleanup"),g(e)},effect(e){p("effect");const n=ee(e),s=te(n,n.from,o,l);g(s,s.fence)},event(e,n,s){p("event");const t=ne(e,n,s),d=re(t,o,t.from,l);let c,i=Promise.resolve();g(async()=>{const h=d.close();try{await i,await(c==null?void 0:c())}finally{await h}},()=>{d.close()}),i=Promise.resolve(t.subscribe({emit:d.emit,signal:o,source:t.from,timers:y.timers})).then(h=>{if(h!==void 0&&typeof h!="function")throw new TypeError("Model event subscribe must return void or a disposer function.");c=h}).catch(O)},lane(){p("lane");const e=Object.freeze({});return v.set(e,W({id:T("lane")})),e},resource(e,n,s){p("resource");const t=oe(e,n,s),d=P(t.target,t.from,"Model resource target");return p("resource"),ie({key:c=>K(t.key(c)),load:(c,i)=>t.load(c,i),retention:t.retention,source:t.from,target:d,...l===void 0?{}:{reporter:l},...t.retry===void 0?{}:{retry:t.retry}},q)},scope:Object.freeze({keyed:e=>j("keyed",e),switch:e=>j("switch",e),while:e=>j("while",e)}),signal:o,state:m,stream(e,n,s){p("stream");const t=ce(e,n,s),d=P(t.target,t.from,"Model stream target");return p("stream"),ue({backpressure:t.backpressure,connect:(c,i)=>t.connect(c,i),key:c=>K(t.key(c)),retention:t.retention,source:t.from,target:d,...t.consume===void 0?{}:{consume:c=>{var i;return(i=t.consume)==null?void 0:i.call(t,c)}},...l===void 0?{}:{reporter:l},...t.retry===void 0?{}:{retry:t.retry}},I)},timers:y.timers,update:a});return Object.freeze({context:L,drain(){return b!==void 0||(b=(async()=>{const e=[];await Promise.resolve();for(const n of C.splice(0))try{await n.retireGeneration(R)}catch(s){e.push(s)}for(const n of w.splice(0).reverse())try{await n.drain()}catch(s){e.push(s)}for(const n of e)O(n)})()),b},fence(){if(!M){M=!0;for(const e of w)try{e.fence()}catch(n){O(n)}try{u.publishInactive()}finally{y.close()}}},ownsCall:e=>k.has(e)})}export{be as createModelKernel};
2
+ //# sourceMappingURL=model-kernel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-kernel.js","sources":["../src/model-kernel.ts"],"sourcesContent":["import type { Call, ModelContext, OwnedState, Resource } from '@opetope/core';\nimport type {\n Awaitable,\n CallContext,\n CallExecutionContext,\n CallExecutor,\n CallLane,\n ModelLane,\n ResourceRequestKey,\n} from '@opetope/core/internal';\nimport {\n assertCallContextCurrent,\n bindCallTargetToAttachment,\n createAttachmentReadinessController,\n createCallExecutor,\n defineCallLane,\n defineCallTarget,\n inheritCallContextLifetime,\n inheritCallExecutionMetadata,\n invokeCallTargetWithGuard,\n releaseCallExecutionMetadata,\n retireCallContext,\n settleGuardedResult,\n} from '@opetope/core/internal';\n\nimport {\n kernelCallScheduling,\n snapshotCallOnce,\n snapshotCallPolicy,\n snapshotCallSingleFlight,\n} from './call-option-snapshot';\nimport type { CallOnceOption, CallPolicy, CallSingleFlightOption } from './call-option-snapshot';\nimport { snapshotCallsKeys } from './feature-calls';\nimport { openEffect, snapshotEffectOptions } from './feature-effect';\nimport { createEventQueue, snapshotEventOptions } from './feature-event';\nimport { requireRequestKey, selectTargetReadable, snapshotFeatureResourceOptions } from './feature-resource';\nimport { createReactiveScopeNode, createReactiveScopeState } from './feature-scope';\nimport type { ReactiveScopeKind } from './feature-scope';\nimport { snapshotFeatureStreamOptions } from './feature-stream';\nimport { createTimerRegistry } from './feature-timers';\nimport type { FeatureActivityOwner } from './inspection-activity';\nimport { createResourceController } from './resource-controller';\nimport { reportRuntimeFailure } from './runtime-error-reporting';\nimport type { RuntimeErrorReporter } from './runtime-error-reporting';\nimport { createStreamController } from './stream-controller';\n\ntype Disposer = () => Awaitable<void>;\ntype OwnedNode = { readonly drain: Disposer; readonly fence: () => void };\ntype ModelStateFactory = <Value>(initial: Value) => OwnedState<Value>;\ntype ModelStateWriter = <Value>(state: OwnedState<Value>, value: Value) => void;\n\ninterface ModelKernel {\n readonly context: ModelContext;\n readonly drain: () => Promise<void>;\n readonly fence: () => void;\n readonly ownsCall: (target: object) => boolean;\n}\n\nconst modelLanes = new WeakMap<object, CallLane>();\nconst callOptionKeys = new Set<PropertyKey>(['lane', 'once', 'policy', 'run', 'singleFlight']);\nconst callsOptionKeys = new Set<PropertyKey>(['lane', 'policy']);\n\ntype ModelCallSnapshot = {\n readonly lane: CallLane | undefined;\n readonly once: CallOnceOption<unknown> | undefined;\n readonly policy: CallPolicy;\n readonly run: (input: unknown, context: CallContext) => unknown;\n readonly singleFlight: CallSingleFlightOption<unknown> | undefined;\n};\n\nfunction requireFunction<Callable>(value: unknown, label: string): Callable {\n if (typeof value !== 'function') throw new TypeError(`${label} must be a function.`);\n\n return value as Callable;\n}\n\nfunction snapshotModelCallLane(value: unknown, policy: CallPolicy): CallLane | undefined {\n if (value === undefined) return undefined;\n\n const lane = modelLanes.get(value as object);\n\n if (lane === undefined) throw new TypeError('Model call lane is not authentic.');\n\n if (policy === 'parallel') throw new TypeError('Parallel model calls cannot declare a lane.');\n\n return lane;\n}\n\nfunction snapshotModelCall(options: unknown): ModelCallSnapshot {\n if (typeof options !== 'object' || options === null) throw new TypeError('Model call options must be a record.');\n\n for (const key of Reflect.ownKeys(options)) {\n if (!callOptionKeys.has(key)) throw new TypeError(`Model call options contain unknown field ${String(key)}.`);\n }\n\n const source = options as Record<string, unknown>;\n const policy = snapshotCallPolicy(source['policy'], 'Model call');\n\n return Object.freeze({\n lane: snapshotModelCallLane(source['lane'], policy),\n once: snapshotCallOnce(source['once'], 'Model call'),\n policy,\n run: requireFunction<ModelCallSnapshot['run']>(source['run'], 'Model call run'),\n singleFlight: snapshotCallSingleFlight(source['singleFlight'], 'Model call'),\n });\n}\n\ntype ModelCallsSelection = {\n readonly lane: unknown;\n readonly methods: Readonly<Record<string, (input: unknown, signal: AbortSignal) => unknown>>;\n readonly policy: unknown;\n readonly source: object;\n};\n\nfunction snapshotModelCallsOptions(value: unknown): { readonly lane: unknown; readonly policy: unknown } {\n if (value === undefined) return { lane: undefined, policy: undefined };\n\n if (typeof value !== 'object' || value === null) throw new TypeError('Model calls options must be a record.');\n\n for (const key of Reflect.ownKeys(value)) {\n if (!callsOptionKeys.has(key)) throw new TypeError(`Model calls options contain unknown field ${String(key)}.`);\n }\n\n const record = value as Record<string, unknown>;\n\n // D185: the batch form declares the policy where the calls are created, exactly like the single form.\n return { lane: record['lane'], policy: record['policy'] };\n}\n\n/**\n * A model selects calls from a value it already holds, so an absent or non-callable member is an authoring mistake\n * this line can name; a feature has to wait for the adapter and checks the same thing on invocation (D143).\n */\nfunction snapshotModelCalls(source: unknown, keys: unknown, options: unknown): ModelCallsSelection {\n if (typeof source !== 'object' || source === null) throw new TypeError('Model calls source must be a record.');\n\n const record = source as Readonly<Record<string, unknown>>;\n const methods: Record<string, (input: unknown, signal: AbortSignal) => unknown> = {};\n\n for (const key of snapshotCallsKeys(keys, 'Model calls')) {\n if (typeof record[key] !== 'function') throw new TypeError(`Model calls source field ${key} is not a method.`);\n\n methods[key] = record[key] as (input: unknown, signal: AbortSignal) => unknown;\n }\n\n const selected = snapshotModelCallsOptions(options);\n\n return Object.freeze({ lane: selected.lane, methods: Object.freeze(methods), policy: selected.policy, source });\n}\n\n/** The call body sees the same context shape a feature call sees: nested calls inherit cancellation and lane. */\nfunction runModelCall(\n snapshot: ModelCallSnapshot,\n input: unknown,\n parent: CallContext,\n executionContext: CallExecutionContext,\n): unknown {\n const callContext: CallContext & { readonly invoke: (target: unknown, input: unknown) => Promise<unknown> } =\n Object.freeze({\n invoke(target: unknown, nested: unknown): Promise<unknown> {\n try {\n assertCallContextCurrent(callContext);\n\n return Promise.resolve(\n invokeCallTargetWithGuard(target as Call<unknown, unknown>, nested, callContext, () =>\n assertCallContextCurrent(callContext),\n ),\n );\n } catch (error) {\n return Promise.reject(error);\n }\n },\n signal: executionContext.signal,\n throwIfAborted(): void {\n assertCallContextCurrent(callContext);\n },\n });\n const assertCurrent = (): void => assertCallContextCurrent(callContext);\n let result: unknown;\n\n try {\n inheritCallContextLifetime(parent, callContext);\n inheritCallExecutionMetadata(callContext, callContext);\n result = snapshot.run(input, callContext);\n } catch (error) {\n releaseCallExecutionMetadata(callContext);\n retireCallContext(callContext);\n\n throw error;\n }\n\n return settleGuardedResult(result, {\n assertCurrent,\n finalize: () => {\n releaseCallExecutionMetadata(callContext);\n retireCallContext(callContext);\n },\n // The executor cancels callers independently; keep its body pending until the original work settles.\n waitForPhysicalSettlement: true,\n });\n}\n\n/**\n * A model owns its nodes: they are created when the generation opens the model and released in the same drain. The\n * readiness controller is the fence, so a call after retire is a cancellation and never a product failure (D73).\n */\nfunction createModelKernel(\n id: string,\n signal: AbortSignal,\n reporter: RuntimeErrorReporter | undefined,\n state: ModelStateFactory,\n update: ModelStateWriter,\n activity?: FeatureActivityOwner,\n): ModelKernel {\n const attachment = createAttachmentReadinessController({ id });\n attachment.publishReady(attachment.beginOpen());\n const timerRegistry = createTimerRegistry(signal, reporter);\n const executors: CallExecutor<unknown, unknown>[] = [];\n const nodes: OwnedNode[] = [];\n const ownedCalls = new WeakSet<object>();\n const generation = Object.freeze({});\n let drainPromise: Promise<void> | undefined;\n let fenced = false;\n let ordinal = 0;\n const nextId = (kind: string): string => {\n ordinal += 1;\n\n return `${id}.${kind}.${String(ordinal)}`;\n };\n const report = (error: unknown): void => reportRuntimeFailure(error, reporter);\n /**\n * Every owned node is released by the same drain, so building one after the fence would build something nobody\n * Releases. `cleanup` and `timers` already refused; the rest refuse the same way (D107).\n */\n const assertOpen = (what: string): void => {\n if (fenced) throw new TypeError(`Model ${what} is unavailable after retire.`);\n };\n const registerNode = (drain: Disposer, fence: () => void = () => undefined): void => {\n nodes.push({ drain, fence });\n\n // A source callback can retire its model while this node is still being constructed.\n if (fenced) fence();\n };\n const openScope = (kind: ReactiveScopeKind, value: unknown): void => {\n assertOpen(`scope.${kind}`);\n const node = createReactiveScopeNode(kind, nextId(`scope.${kind}`), value);\n const scope = createReactiveScopeState(node.from, signal, node.createController(reporter), reporter);\n registerNode(scope.close, scope.fence);\n void scope.open().catch(report);\n };\n const materialize = <Data, Key extends ResourceRequestKey>(\n controller: Resource<Data, Key> & { readonly close: () => Promise<void>; readonly fence: () => void },\n kind: 'resource' | 'stream',\n ): Resource<Data, Key> => {\n registerNode(controller.close, controller.fence);\n activity?.registerResource(kind, controller);\n\n return controller;\n };\n const registerResource = <Data, Key extends ResourceRequestKey>(\n controller: Parameters<typeof materialize<Data, Key>>[0],\n ): void => void materialize(controller, 'resource');\n const registerStream = <Data, Key extends ResourceRequestKey>(\n controller: Parameters<typeof materialize<Data, Key>>[0],\n ): void => void materialize(controller, 'stream');\n\n const createModelCall = (options: unknown): Call<unknown, unknown> => {\n assertOpen('call');\n const snapshot = snapshotModelCall(options);\n const targetId = nextId('call');\n const executor = createCallExecutor<unknown, unknown>(\n {\n id: targetId,\n ...(snapshot.once === undefined ? {} : { once: snapshot.once }),\n scheduling: kernelCallScheduling(snapshot.policy, snapshot.lane),\n ...(snapshot.singleFlight === undefined ? {} : { singleFlight: snapshot.singleFlight }),\n },\n activity,\n );\n executors.push(executor);\n activity?.registerCall(executor);\n\n const target = bindCallTargetToAttachment(\n defineCallTarget<unknown, unknown>({\n id: targetId,\n run: (input, parent) =>\n executor.start(input, callContext => runModelCall(snapshot, input, parent, callContext), {\n generation,\n parent,\n signal,\n }),\n }),\n attachment.ref,\n );\n ownedCalls.add(target);\n\n return target;\n };\n\n const context: ModelContext = Object.freeze({\n call: createModelCall,\n calls(source: unknown, keys: unknown, options?: unknown) {\n assertOpen('calls');\n const selection = snapshotModelCalls(source, keys, options);\n const entries = Object.entries(selection.methods).map(\n ([key, method]): readonly [string, Call<unknown, unknown>] => [\n key,\n createModelCall({\n lane: selection.lane,\n policy: selection.policy,\n run: (input: unknown, callContext: { readonly signal: AbortSignal }): unknown =>\n method.call(selection.source, input, callContext.signal),\n }),\n ],\n );\n\n return Object.freeze(Object.fromEntries(entries));\n },\n cleanup(disposer: unknown) {\n if (typeof disposer !== 'function') throw new TypeError('Model cleanup expects a disposer function.');\n\n // Fenced means the drain already ran, so a late registration would never be released (D95).\n assertOpen('cleanup');\n\n registerNode(disposer as Disposer);\n },\n effect(options: unknown) {\n assertOpen('effect');\n const snapshot = snapshotEffectOptions(options);\n const effect = openEffect(snapshot, snapshot.from, signal, reporter);\n registerNode(effect, effect.fence);\n },\n event(from: unknown, subscribe: unknown, options: unknown) {\n assertOpen('event');\n const snapshot = snapshotEventOptions(from, subscribe, options);\n const queue = createEventQueue(snapshot, signal, snapshot.from, reporter);\n let disposer: Disposer | undefined;\n let opening = Promise.resolve();\n registerNode(\n async () => {\n const closing = queue.close();\n\n try {\n await opening;\n await disposer?.();\n } finally {\n await closing;\n }\n },\n () => void queue.close(),\n );\n opening = Promise.resolve(\n snapshot.subscribe({ emit: queue.emit, signal, source: snapshot.from, timers: timerRegistry.timers }),\n )\n .then(opened => {\n if (opened !== undefined && typeof opened !== 'function') {\n throw new TypeError('Model event subscribe must return void or a disposer function.');\n }\n\n disposer = opened as Disposer | undefined;\n })\n .catch(report);\n },\n lane(): ModelLane {\n assertOpen('lane');\n const ref = Object.freeze({});\n modelLanes.set(ref, defineCallLane({ id: nextId('lane') }));\n\n return ref as unknown as ModelLane;\n },\n resource(from: unknown, target: unknown, options: unknown) {\n assertOpen('resource');\n const snapshot = snapshotFeatureResourceOptions(from, target, options);\n const selected = selectTargetReadable(snapshot.target, snapshot.from, 'Model resource target');\n assertOpen('resource');\n\n return createResourceController(\n {\n key: selected => requireRequestKey(snapshot.key(selected)),\n load: (selected, loadContext) => snapshot.load(selected, loadContext),\n retention: snapshot.retention,\n source: snapshot.from,\n target: selected,\n ...(reporter === undefined ? {} : { reporter }),\n ...(snapshot.retry === undefined ? {} : { retry: snapshot.retry }),\n },\n registerResource,\n );\n },\n scope: Object.freeze({\n keyed: (options: unknown) => openScope('keyed', options),\n switch: (options: unknown) => openScope('switch', options),\n while: (options: unknown) => openScope('while', options),\n }),\n signal,\n state,\n stream(from: unknown, target: unknown, options: unknown) {\n assertOpen('stream');\n const snapshot = snapshotFeatureStreamOptions(from, target, options);\n const selected = selectTargetReadable(snapshot.target, snapshot.from, 'Model stream target');\n assertOpen('stream');\n\n return createStreamController(\n {\n backpressure: snapshot.backpressure,\n connect: (selected, connectContext) => snapshot.connect(selected, connectContext) as never,\n key: selected => requireRequestKey(snapshot.key(selected)),\n retention: snapshot.retention,\n source: snapshot.from,\n target: selected,\n ...(snapshot.consume === undefined\n ? {}\n : {\n consume: (consumeContext: Parameters<NonNullable<typeof snapshot.consume>>[0]) =>\n snapshot.consume?.(consumeContext) as never,\n }),\n ...(reporter === undefined ? {} : { reporter }),\n ...(snapshot.retry === undefined ? {} : { retry: snapshot.retry }),\n },\n registerStream,\n );\n },\n timers: timerRegistry.timers,\n update,\n }) as unknown as ModelContext;\n\n return Object.freeze({\n context,\n drain(): Promise<void> {\n if (drainPromise !== undefined) return drainPromise;\n\n drainPromise = (async () => {\n const failures: unknown[] = [];\n // Join nodes whose synchronous construction reentered close before they could register their drain.\n await Promise.resolve();\n\n for (const executor of executors.splice(0)) {\n try {\n await executor.retireGeneration(generation);\n } catch (error) {\n failures.push(error);\n }\n }\n\n // Reverse registration order: what a model built last is released first, cleanup included (D95).\n for (const node of nodes.splice(0).reverse()) {\n try {\n await node.drain();\n } catch (error) {\n failures.push(error);\n }\n }\n\n for (const failure of failures) report(failure);\n })();\n\n return drainPromise;\n },\n fence(): void {\n if (fenced) return;\n\n fenced = true;\n\n for (const node of nodes) {\n try {\n node.fence();\n } catch (error) {\n report(error);\n }\n }\n\n try {\n attachment.publishInactive();\n } finally {\n timerRegistry.close();\n }\n },\n ownsCall: (target: object): boolean => ownedCalls.has(target),\n });\n}\n\nexport { createModelKernel };\nexport type { ModelKernel };\n"],"names":["modelLanes","callOptionKeys","callsOptionKeys","requireFunction","value","label","snapshotModelCallLane","policy","lane","snapshotModelCall","options","key","source","snapshotCallPolicy","snapshotCallOnce","snapshotCallSingleFlight","snapshotModelCallsOptions","record","snapshotModelCalls","keys","methods","snapshotCallsKeys","selected","runModelCall","snapshot","input","parent","executionContext","callContext","target","nested","assertCallContextCurrent","invokeCallTargetWithGuard","error","assertCurrent","result","inheritCallContextLifetime","inheritCallExecutionMetadata","releaseCallExecutionMetadata","retireCallContext","settleGuardedResult","createModelKernel","id","signal","reporter","state","update","activity","attachment","createAttachmentReadinessController","timerRegistry","createTimerRegistry","executors","nodes","ownedCalls","generation","drainPromise","fenced","ordinal","nextId","kind","report","reportRuntimeFailure","assertOpen","what","registerNode","drain","fence","openScope","node","createReactiveScopeNode","scope","createReactiveScopeState","materialize","controller","registerResource","registerStream","createModelCall","targetId","executor","createCallExecutor","kernelCallScheduling","bindCallTargetToAttachment","defineCallTarget","context","selection","entries","method","disposer","snapshotEffectOptions","effect","openEffect","from","subscribe","snapshotEventOptions","queue","createEventQueue","opening","closing","opened","ref","defineCallLane","snapshotFeatureResourceOptions","selectTargetReadable","createResourceController","requireRequestKey","loadContext","snapshotFeatureStreamOptions","createStreamController","connectContext","consumeContext","_a","failures","failure"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Call } from '@opetope/core';
2
+ import type { CallContext } from '@opetope/core/internal';
3
+ import type { AttachmentCallRef } from './attachment-call-declaration.js';
4
+ type LocalCallResolver = <Input, Output>(call: AttachmentCallRef<Input, Output>) => Call<Input, Output>;
5
+ declare function bindLocalCallResolver(context: CallContext, resolver: LocalCallResolver): void;
6
+ declare function resolveLocalCallTarget<Input, Output>(context: CallContext, call: AttachmentCallRef<Input, Output>): Call<Input, Output>;
7
+ export { bindLocalCallResolver, resolveLocalCallTarget };
@@ -0,0 +1,2 @@
1
+ const o=new WeakMap;function a(e,l){if(o.has(e))throw new TypeError("Call context already has a local resolver.");o.set(e,l)}function n(e,l){const r=o.get(e);if(r===void 0)throw new TypeError("Call context cannot resolve a local call ref.");return r(l)}export{a as bindLocalCallResolver,n as resolveLocalCallTarget};
2
+ //# sourceMappingURL=module-call-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-call-context.js","sources":["../src/module-call-context.ts"],"sourcesContent":["import type { Call } from '@opetope/core';\nimport type { CallContext } from '@opetope/core/internal';\n\nimport type { AttachmentCallRef } from './attachment-call-declaration';\n\ntype LocalCallResolver = <Input, Output>(call: AttachmentCallRef<Input, Output>) => Call<Input, Output>;\n\nconst localCallResolvers = new WeakMap<object, LocalCallResolver>();\n\nfunction bindLocalCallResolver(context: CallContext, resolver: LocalCallResolver): void {\n if (localCallResolvers.has(context)) throw new TypeError('Call context already has a local resolver.');\n\n localCallResolvers.set(context, resolver);\n}\n\nfunction resolveLocalCallTarget<Input, Output>(\n context: CallContext,\n call: AttachmentCallRef<Input, Output>,\n): Call<Input, Output> {\n const resolver = localCallResolvers.get(context);\n\n if (resolver === undefined) throw new TypeError('Call context cannot resolve a local call ref.');\n\n return resolver(call);\n}\n\nexport { bindLocalCallResolver, resolveLocalCallTarget };\n"],"names":["localCallResolvers","bindLocalCallResolver","context","resolver","resolveLocalCallTarget","call"],"mappings":"AAOA,MAAMA,EAAqB,IAAI,QAE/B,SAASC,EAAsBC,EAAsBC,EAA2B,CAC9E,GAAIH,EAAmB,IAAIE,CAAO,EAAG,MAAM,IAAI,UAAU,4CAA4C,EAErGF,EAAmB,IAAIE,EAASC,CAAQ,CAC1C,CAEA,SAASC,EACPF,EACAG,EAAsC,CAEtC,MAAMF,EAAWH,EAAmB,IAAIE,CAAO,EAE/C,GAAIC,IAAa,OAAW,MAAM,IAAI,UAAU,+CAA+C,EAE/F,OAAOA,EAASE,CAAI,CACtB"}
@@ -0,0 +1,21 @@
1
+ import type { CallContext, CallExecutionContext, CallExecutor, CallInvocation, CallLane } from '@opetope/core/internal';
2
+ import type { CompiledAttachmentCallPolicy } from './attachment-call-declaration.js';
3
+ import type { FeatureActivityOwner } from './inspection-activity.js';
4
+ import type { OwnerGeneration } from './owner-generation.js';
5
+ type ModuleCallRegistry = {
6
+ activity: FeatureActivityOwner | undefined;
7
+ executors: WeakMap<OwnerGeneration, Map<number, Set<CallExecutor<unknown, unknown>>>>;
8
+ lanes: WeakMap<object, WeakMap<object, CallLane>>;
9
+ };
10
+ type ModuleCallInvocation<Input, Output> = Readonly<{
11
+ execute: (context: CallExecutionContext) => Output | PromiseLike<Output>;
12
+ generation: OwnerGeneration;
13
+ input: Input;
14
+ parent: CallContext;
15
+ }>;
16
+ type InvokeModuleCall<Input, Output> = (invocation: ModuleCallInvocation<Input, Output>) => CallInvocation<Output>;
17
+ declare function createModuleCallRegistry(): ModuleCallRegistry;
18
+ declare function retireModuleAttachmentCalls(registry: ModuleCallRegistry, generation: OwnerGeneration, attachmentSlot: number): Promise<void>;
19
+ declare function createModuleCallInvoker<Input, Output>(id: string, attachmentSlot: number, policy: CompiledAttachmentCallPolicy<Input>, registry: ModuleCallRegistry): InvokeModuleCall<Input, Output>;
20
+ export { createModuleCallInvoker, createModuleCallRegistry, retireModuleAttachmentCalls };
21
+ export type { ModuleCallRegistry };
@@ -0,0 +1,2 @@
1
+ import{createCallExecutor as o,defineCallLane as d}from"@opetope/core/internal";import{kernelCallScheduling as c}from"./call-option-snapshot.js";import{getFeatureCallLaneRecord as f}from"./feature-call.js";function g(){return{activity:void 0,executors:new WeakMap,lanes:new WeakMap}}function x(a,u,t,n){let r=a.executors.get(u);r===void 0&&(r=new Map,a.executors.set(u,r));let e=r.get(t);e===void 0&&(e=new Set,r.set(t,e)),e.add(n)}function p(a,u,t){const n=a.executors.get(u),r=n==null?void 0:n.get(t);return r===void 0?Promise.resolve():Promise.all([...r].map(e=>e.retireGeneration(u))).then(()=>{var e;(n==null?void 0:n.get(t))===r&&n.delete(t);for(const i of r)(e=a.activity)==null||e.releaseCall(i)})}function C(a,u){const t=a.lanes.get(u);if(t!==void 0)return t;const n=new WeakMap;return a.lanes.set(u,n),n}function M(a,u,t){const n=C(a,u),r=n.get(t);if(r!==void 0)return r;const e=d({id:f(t).id});return n.set(t,e),e}function k(a,u,t,n){var l;const r=u.once,e=u.singleFlight,i=u.lane===void 0?void 0:M(t,n,u.lane),s=o({id:a,...r===void 0?{}:{once:r},scheduling:c(u.policy,i),...e===void 0?{}:{singleFlight:e}},t.activity);return(l=t.activity)==null||l.registerCall(s),s}function m(a,u,t,n){const r=new WeakMap;return e=>{let i=r.get(e.generation);return i===void 0&&(i=k(a,t,n,e.generation),r.set(e.generation,i),x(n,e.generation,u,i)),i.start(e.input,e.execute,{generation:e.generation,parent:e.parent,signal:e.generation.signal})}}export{m as createModuleCallInvoker,g as createModuleCallRegistry,p as retireModuleAttachmentCalls};
2
+ //# sourceMappingURL=module-call-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-call-runtime.js","sources":["../src/module-call-runtime.ts"],"sourcesContent":["import { createCallExecutor, defineCallLane } from '@opetope/core/internal';\nimport type { CallContext, CallExecutionContext, CallExecutor, CallInvocation, CallLane } from '@opetope/core/internal';\n\nimport type { CompiledAttachmentCallPolicy } from './attachment-call-declaration';\nimport { kernelCallScheduling } from './call-option-snapshot';\nimport { getFeatureCallLaneRecord } from './feature-call';\nimport type { FeatureActivityOwner } from './inspection-activity';\nimport type { OwnerGeneration } from './owner-generation';\n\ntype ModuleCallRegistry = {\n activity: FeatureActivityOwner | undefined;\n executors: WeakMap<OwnerGeneration, Map<number, Set<CallExecutor<unknown, unknown>>>>;\n lanes: WeakMap<object, WeakMap<object, CallLane>>;\n};\n\ntype ModuleCallInvocation<Input, Output> = Readonly<{\n execute: (context: CallExecutionContext) => Output | PromiseLike<Output>;\n generation: OwnerGeneration;\n input: Input;\n parent: CallContext;\n}>;\n\ntype InvokeModuleCall<Input, Output> = (invocation: ModuleCallInvocation<Input, Output>) => CallInvocation<Output>;\n\nfunction createModuleCallRegistry(): ModuleCallRegistry {\n return {\n activity: undefined,\n executors: new WeakMap<OwnerGeneration, Map<number, Set<CallExecutor<unknown, unknown>>>>(),\n lanes: new WeakMap<object, WeakMap<object, CallLane>>(),\n };\n}\n\nfunction registerGenerationExecutor<Input, Output>(\n registry: ModuleCallRegistry,\n generation: OwnerGeneration,\n attachmentSlot: number,\n executor: CallExecutor<Input, Output>,\n): void {\n let byAttachment = registry.executors.get(generation);\n\n if (byAttachment === undefined) {\n byAttachment = new Map();\n registry.executors.set(generation, byAttachment);\n }\n\n let executors = byAttachment.get(attachmentSlot);\n\n if (executors === undefined) {\n executors = new Set();\n byAttachment.set(attachmentSlot, executors);\n }\n\n executors.add(executor as CallExecutor<unknown, unknown>);\n}\n\nfunction retireModuleAttachmentCalls(\n registry: ModuleCallRegistry,\n generation: OwnerGeneration,\n attachmentSlot: number,\n): Promise<void> {\n const byAttachment = registry.executors.get(generation);\n const executors = byAttachment?.get(attachmentSlot);\n\n if (executors === undefined) return Promise.resolve();\n\n return Promise.all([...executors].map(executor => executor.retireGeneration(generation))).then(() => {\n if (byAttachment?.get(attachmentSlot) === executors) byAttachment.delete(attachmentSlot);\n\n for (const executor of executors) registry.activity?.releaseCall(executor);\n });\n}\n\nfunction generationLaneMap(registry: ModuleCallRegistry, generation: OwnerGeneration): WeakMap<object, CallLane> {\n const existing = registry.lanes.get(generation);\n\n if (existing !== undefined) return existing;\n\n const created = new WeakMap<object, CallLane>();\n registry.lanes.set(generation, created);\n\n return created;\n}\n\nfunction materializeSharedLane(registry: ModuleCallRegistry, generation: OwnerGeneration, laneRef: object): CallLane {\n const lanes = generationLaneMap(registry, generation);\n const existing = lanes.get(laneRef);\n\n if (existing !== undefined) return existing;\n\n const created = defineCallLane({ id: getFeatureCallLaneRecord(laneRef).id });\n lanes.set(laneRef, created);\n\n return created;\n}\n\nfunction createGenerationExecutor<Input, Output>(\n id: string,\n policy: CompiledAttachmentCallPolicy<Input>,\n registry: ModuleCallRegistry,\n generation: OwnerGeneration,\n): CallExecutor<Input, Output> {\n const once = policy.once;\n const singleFlight = policy.singleFlight;\n const lane = policy.lane === undefined ? undefined : materializeSharedLane(registry, generation, policy.lane);\n\n const executor = createCallExecutor<Input, Output>(\n {\n id,\n ...(once === undefined ? {} : { once }),\n scheduling: kernelCallScheduling(policy.policy, lane),\n ...(singleFlight === undefined ? {} : { singleFlight }),\n },\n registry.activity,\n );\n registry.activity?.registerCall(executor as CallExecutor<unknown, unknown>);\n\n return executor;\n}\n\nfunction createModuleCallInvoker<Input, Output>(\n id: string,\n attachmentSlot: number,\n policy: CompiledAttachmentCallPolicy<Input>,\n registry: ModuleCallRegistry,\n): InvokeModuleCall<Input, Output> {\n const executors = new WeakMap<OwnerGeneration, CallExecutor<Input, Output>>();\n\n return invocation => {\n let executor = executors.get(invocation.generation);\n\n if (executor === undefined) {\n executor = createGenerationExecutor(id, policy, registry, invocation.generation);\n executors.set(invocation.generation, executor);\n registerGenerationExecutor(registry, invocation.generation, attachmentSlot, executor);\n }\n\n return executor.start(invocation.input, invocation.execute, {\n generation: invocation.generation,\n parent: invocation.parent,\n signal: invocation.generation.signal,\n });\n };\n}\n\nexport { createModuleCallInvoker, createModuleCallRegistry, retireModuleAttachmentCalls };\nexport type { ModuleCallRegistry };\n"],"names":["createModuleCallRegistry","registerGenerationExecutor","registry","generation","attachmentSlot","executor","byAttachment","executors","retireModuleAttachmentCalls","_a","generationLaneMap","existing","created","materializeSharedLane","laneRef","lanes","defineCallLane","getFeatureCallLaneRecord","createGenerationExecutor","id","policy","once","singleFlight","lane","createCallExecutor","kernelCallScheduling","createModuleCallInvoker","invocation"],"mappings":"8MAwBA,SAASA,GAAwB,CAC/B,MAAO,CACL,SAAU,OACV,UAAW,IAAI,QACf,MAAO,IAAI,QAEf,CAEA,SAASC,EACPC,EACAC,EACAC,EACAC,EAAqC,CAErC,IAAIC,EAAeJ,EAAS,UAAU,IAAIC,CAAU,EAEhDG,IAAiB,SACnBA,EAAe,IAAI,IACnBJ,EAAS,UAAU,IAAIC,EAAYG,CAAY,GAGjD,IAAIC,EAAYD,EAAa,IAAIF,CAAc,EAE3CG,IAAc,SAChBA,EAAY,IAAI,IAChBD,EAAa,IAAIF,EAAgBG,CAAS,GAG5CA,EAAU,IAAIF,CAA0C,CAC1D,CAEA,SAASG,EACPN,EACAC,EACAC,EAAsB,CAEtB,MAAME,EAAeJ,EAAS,UAAU,IAAIC,CAAU,EAChDI,EAAYD,GAAA,YAAAA,EAAc,IAAIF,GAEpC,OAAIG,IAAc,OAAkB,QAAQ,QAAO,EAE5C,QAAQ,IAAI,CAAC,GAAGA,CAAS,EAAE,IAAIF,GAAYA,EAAS,iBAAiBF,CAAU,CAAC,CAAC,EAAE,KAAK,IAAK,QAC9FG,GAAA,YAAAA,EAAc,IAAIF,MAAoBG,GAAWD,EAAa,OAAOF,CAAc,EAEvF,UAAWC,KAAYE,GAAWE,EAAAP,EAAS,WAAT,MAAAO,EAAmB,YAAYJ,EACnE,CAAC,CACH,CAEA,SAASK,EAAkBR,EAA8BC,EAA2B,CAClF,MAAMQ,EAAWT,EAAS,MAAM,IAAIC,CAAU,EAE9C,GAAIQ,IAAa,OAAW,OAAOA,EAEnC,MAAMC,EAAU,IAAI,QACpB,OAAAV,EAAS,MAAM,IAAIC,EAAYS,CAAO,EAE/BA,CACT,CAEA,SAASC,EAAsBX,EAA8BC,EAA6BW,EAAe,CACvG,MAAMC,EAAQL,EAAkBR,EAAUC,CAAU,EAC9CQ,EAAWI,EAAM,IAAID,CAAO,EAElC,GAAIH,IAAa,OAAW,OAAOA,EAEnC,MAAMC,EAAUI,EAAe,CAAE,GAAIC,EAAyBH,CAAO,EAAE,GAAI,EAC3E,OAAAC,EAAM,IAAID,EAASF,CAAO,EAEnBA,CACT,CAEA,SAASM,EACPC,EACAC,EACAlB,EACAC,EAA2B,OAE3B,MAAMkB,EAAOD,EAAO,KACdE,EAAeF,EAAO,aACtBG,EAAOH,EAAO,OAAS,OAAY,OAAYP,EAAsBX,EAAUC,EAAYiB,EAAO,IAAI,EAEtGf,EAAWmB,EACf,CACE,GAAAL,EACA,GAAIE,IAAS,OAAY,GAAK,CAAE,KAAAA,CAAI,EACpC,WAAYI,EAAqBL,EAAO,OAAQG,CAAI,EACpD,GAAID,IAAiB,OAAY,GAAK,CAAE,aAAAA,CAAY,CACrD,EACDpB,EAAS,QAAQ,EAEnB,OAAAO,EAAAP,EAAS,WAAT,MAAAO,EAAmB,aAAaJ,GAEzBA,CACT,CAEA,SAASqB,EACPP,EACAf,EACAgB,EACAlB,EAA4B,CAE5B,MAAMK,EAAY,IAAI,QAEtB,OAAOoB,GAAa,CAClB,IAAItB,EAAWE,EAAU,IAAIoB,EAAW,UAAU,EAElD,OAAItB,IAAa,SACfA,EAAWa,EAAyBC,EAAIC,EAAQlB,EAAUyB,EAAW,UAAU,EAC/EpB,EAAU,IAAIoB,EAAW,WAAYtB,CAAQ,EAC7CJ,EAA2BC,EAAUyB,EAAW,WAAYvB,EAAgBC,CAAQ,GAG/EA,EAAS,MAAMsB,EAAW,MAAOA,EAAW,QAAS,CAC1D,WAAYA,EAAW,WACvB,OAAQA,EAAW,OACnB,OAAQA,EAAW,WAAW,MAC/B,CAAA,CACH,CACF"}