@primafuture/contrib-kit-react 1.0.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 (128) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +294 -0
  3. package/dist/contribution-component.d.ts +82 -0
  4. package/dist/contribution-component.d.ts.map +1 -0
  5. package/dist/contribution-component.js +12 -0
  6. package/dist/contribution-component.js.map +1 -0
  7. package/dist/extension-outlet.d.ts +155 -0
  8. package/dist/extension-outlet.d.ts.map +1 -0
  9. package/dist/extension-outlet.js +229 -0
  10. package/dist/extension-outlet.js.map +1 -0
  11. package/dist/extension-registry-provider.d.ts +26 -0
  12. package/dist/extension-registry-provider.d.ts.map +1 -0
  13. package/dist/extension-registry-provider.js +82 -0
  14. package/dist/extension-registry-provider.js.map +1 -0
  15. package/dist/index.d.ts +22 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +14 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/internal/adapter-configuration.d.ts +54 -0
  20. package/dist/internal/adapter-configuration.d.ts.map +1 -0
  21. package/dist/internal/adapter-configuration.js +89 -0
  22. package/dist/internal/adapter-configuration.js.map +1 -0
  23. package/dist/internal/adapter-context.d.ts +24 -0
  24. package/dist/internal/adapter-context.d.ts.map +1 -0
  25. package/dist/internal/adapter-context.js +23 -0
  26. package/dist/internal/adapter-context.js.map +1 -0
  27. package/dist/internal/adapter-registry-bridge.d.ts +58 -0
  28. package/dist/internal/adapter-registry-bridge.d.ts.map +1 -0
  29. package/dist/internal/adapter-registry-bridge.js +494 -0
  30. package/dist/internal/adapter-registry-bridge.js.map +1 -0
  31. package/dist/internal/adapter-registry-protocol.d.ts +53 -0
  32. package/dist/internal/adapter-registry-protocol.d.ts.map +1 -0
  33. package/dist/internal/adapter-registry-protocol.js +182 -0
  34. package/dist/internal/adapter-registry-protocol.js.map +1 -0
  35. package/dist/internal/adapter-scope.d.ts +87 -0
  36. package/dist/internal/adapter-scope.d.ts.map +1 -0
  37. package/dist/internal/adapter-scope.js +346 -0
  38. package/dist/internal/adapter-scope.js.map +1 -0
  39. package/dist/internal/implementation-classifier.d.ts +21 -0
  40. package/dist/internal/implementation-classifier.d.ts.map +1 -0
  41. package/dist/internal/implementation-classifier.js +39 -0
  42. package/dist/internal/implementation-classifier.js.map +1 -0
  43. package/dist/internal/managed-lazy-generation.d.ts +100 -0
  44. package/dist/internal/managed-lazy-generation.d.ts.map +1 -0
  45. package/dist/internal/managed-lazy-generation.js +419 -0
  46. package/dist/internal/managed-lazy-generation.js.map +1 -0
  47. package/dist/internal/outlet-commit-lease.d.ts +46 -0
  48. package/dist/internal/outlet-commit-lease.d.ts.map +1 -0
  49. package/dist/internal/outlet-commit-lease.js +137 -0
  50. package/dist/internal/outlet-commit-lease.js.map +1 -0
  51. package/dist/internal/outlet-error-pipeline.d.ts +122 -0
  52. package/dist/internal/outlet-error-pipeline.d.ts.map +1 -0
  53. package/dist/internal/outlet-error-pipeline.js +214 -0
  54. package/dist/internal/outlet-error-pipeline.js.map +1 -0
  55. package/dist/internal/outlet-input.d.ts +42 -0
  56. package/dist/internal/outlet-input.d.ts.map +1 -0
  57. package/dist/internal/outlet-input.js +86 -0
  58. package/dist/internal/outlet-input.js.map +1 -0
  59. package/dist/internal/outlet-membership-boundary.d.ts +93 -0
  60. package/dist/internal/outlet-membership-boundary.d.ts.map +1 -0
  61. package/dist/internal/outlet-membership-boundary.js +710 -0
  62. package/dist/internal/outlet-membership-boundary.js.map +1 -0
  63. package/dist/internal/outlet-membership.d.ts +31 -0
  64. package/dist/internal/outlet-membership.d.ts.map +1 -0
  65. package/dist/internal/outlet-membership.js +65 -0
  66. package/dist/internal/outlet-membership.js.map +1 -0
  67. package/dist/internal/outlet-projection.d.ts +102 -0
  68. package/dist/internal/outlet-projection.d.ts.map +1 -0
  69. package/dist/internal/outlet-projection.js +228 -0
  70. package/dist/internal/outlet-projection.js.map +1 -0
  71. package/dist/internal/outlet-reporter-boundary.d.ts +42 -0
  72. package/dist/internal/outlet-reporter-boundary.d.ts.map +1 -0
  73. package/dist/internal/outlet-reporter-boundary.js +57 -0
  74. package/dist/internal/outlet-reporter-boundary.js.map +1 -0
  75. package/dist/internal/public-input-capture.d.ts +13 -0
  76. package/dist/internal/public-input-capture.d.ts.map +1 -0
  77. package/dist/internal/public-input-capture.js +34 -0
  78. package/dist/internal/public-input-capture.js.map +1 -0
  79. package/dist/internal/resolved-contributions-query.d.ts +42 -0
  80. package/dist/internal/resolved-contributions-query.d.ts.map +1 -0
  81. package/dist/internal/resolved-contributions-query.js +203 -0
  82. package/dist/internal/resolved-contributions-query.js.map +1 -0
  83. package/dist/react-adapter-diagnostics.d.ts +199 -0
  84. package/dist/react-adapter-diagnostics.d.ts.map +1 -0
  85. package/dist/react-adapter-diagnostics.js +257 -0
  86. package/dist/react-adapter-diagnostics.js.map +1 -0
  87. package/dist/react-adapter-error.d.ts +35 -0
  88. package/dist/react-adapter-error.d.ts.map +1 -0
  89. package/dist/react-adapter-error.js +37 -0
  90. package/dist/react-adapter-error.js.map +1 -0
  91. package/dist/react-extension-point.d.ts +26 -0
  92. package/dist/react-extension-point.d.ts.map +1 -0
  93. package/dist/react-extension-point.js +100 -0
  94. package/dist/react-extension-point.js.map +1 -0
  95. package/dist/react-lazy-contribution.d.ts +40 -0
  96. package/dist/react-lazy-contribution.d.ts.map +1 -0
  97. package/dist/react-lazy-contribution.js +18 -0
  98. package/dist/react-lazy-contribution.js.map +1 -0
  99. package/dist/resolved-contributions.d.ts +90 -0
  100. package/dist/resolved-contributions.d.ts.map +1 -0
  101. package/dist/resolved-contributions.js +455 -0
  102. package/dist/resolved-contributions.js.map +1 -0
  103. package/package.json +47 -0
  104. package/src/contribution-component.ts +118 -0
  105. package/src/extension-outlet.ts +590 -0
  106. package/src/extension-registry-provider.ts +179 -0
  107. package/src/index.ts +72 -0
  108. package/src/internal/adapter-configuration.ts +181 -0
  109. package/src/internal/adapter-context.ts +43 -0
  110. package/src/internal/adapter-registry-bridge.ts +723 -0
  111. package/src/internal/adapter-registry-protocol.ts +365 -0
  112. package/src/internal/adapter-scope.ts +500 -0
  113. package/src/internal/implementation-classifier.ts +59 -0
  114. package/src/internal/managed-lazy-generation.ts +540 -0
  115. package/src/internal/outlet-commit-lease.ts +216 -0
  116. package/src/internal/outlet-error-pipeline.ts +447 -0
  117. package/src/internal/outlet-input.ts +264 -0
  118. package/src/internal/outlet-membership-boundary.ts +1048 -0
  119. package/src/internal/outlet-membership.ts +125 -0
  120. package/src/internal/outlet-projection.ts +511 -0
  121. package/src/internal/outlet-reporter-boundary.ts +105 -0
  122. package/src/internal/public-input-capture.ts +55 -0
  123. package/src/internal/resolved-contributions-query.ts +318 -0
  124. package/src/react-adapter-diagnostics.ts +457 -0
  125. package/src/react-adapter-error.ts +88 -0
  126. package/src/react-extension-point.ts +181 -0
  127. package/src/react-lazy-contribution.ts +66 -0
  128. package/src/resolved-contributions.ts +895 -0
@@ -0,0 +1,1048 @@
1
+ import type * as contribKitCore from "@primafuture/contrib-kit-core";
2
+ import * as react from "react";
3
+
4
+ import type * as adapterScope from "./adapter-scope.js";
5
+ import type * as adapterConfiguration from "./adapter-configuration.js";
6
+ import type * as implementationClassifier from "./implementation-classifier.js";
7
+ import * as managedLazyGeneration from "./managed-lazy-generation.js";
8
+ import type * as outletCommitLease from "./outlet-commit-lease.js";
9
+ import * as outletErrorPipeline from "./outlet-error-pipeline.js";
10
+ import * as outletInput from "./outlet-input.js";
11
+ import type * as outletMembership from "./outlet-membership.js";
12
+ import * as outletReporterBoundary from "./outlet-reporter-boundary.js";
13
+ import type * as outletProjection from "./outlet-projection.js";
14
+ import type * as contributionComponent from "../contribution-component.js";
15
+ import * as reactAdapterDiagnostics from "../react-adapter-diagnostics.js";
16
+ import type * as reactAdapterError from "../react-adapter-error.js";
17
+ import * as reactAdapterErrorRuntime from "../react-adapter-error.js";
18
+ import type * as reactExtensionPoint from "../react-extension-point.js";
19
+
20
+ /** Props jedné interní package-owned membership boundary. */
21
+ export interface OutletMembershipBoundaryProps<
22
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
23
+ > {
24
+ /** Read-once outlet input pro current render snapshot. */
25
+ readonly input: outletInput.CapturedOutletInput<Point>;
26
+ /** Exact projected membership včetně retained local tokenu. */
27
+ readonly membership: outletMembership.OutletMembershipEntry<Point>;
28
+ /** Commit-owned outlet lease; server a první hydration render ji ještě nemají. */
29
+ readonly outletLease: outletCommitLease.OutletCommitLease | undefined;
30
+ /** Exact raw registry reference jako první osa identity. */
31
+ readonly rawRegistry: object;
32
+ /** Stabilní adapter scope vlastnící boundary ID allocator. */
33
+ readonly scope: adapterScope.AdapterScopeRuntime;
34
+ /** Exact provider/outlet generation pro commit acquire. */
35
+ readonly scopeGeneration: adapterScope.AdapterScopeGeneration;
36
+ }
37
+
38
+ /** Opaque generation token remountující pouze affected membership subtree. */
39
+ interface OutletRetryGenerationToken {
40
+ /** Privátní runtime-prázdný marker. */
41
+ readonly kind?: never;
42
+ }
43
+
44
+ /** Render mode jedné membership retry generation. */
45
+ type OutletMembershipRenderMode =
46
+ | "rendering"
47
+ | "captured"
48
+ | "hidden"
49
+ | "fallback"
50
+ | "escalating";
51
+
52
+ /** Boundary-local managed-lazy presentation nezávislá na Core membership seedu. */
53
+ type OutletManagedLazyStatus = "inactive" | "loading" | "ready" | "failed";
54
+
55
+ /** Kompletní class state včetně identity a current error presentation. */
56
+ interface OutletMembershipBoundaryState {
57
+ /** Přesný cause zachycený React boundary lifecyclem. */
58
+ readonly capturedCause: unknown;
59
+ /** Exact cause připravený pro host escalation. */
60
+ readonly escalationCause: unknown;
61
+ /** Opaque attempt token vzniklý pouze při captured failure. */
62
+ readonly errorAttemptToken: object | undefined;
63
+ /** Zda state skutečně nese captured cause i při undefined hodnotě. */
64
+ readonly hasCapturedCause: boolean;
65
+ /** Eager componenta vrácená current lazy generation. */
66
+ readonly lazyComponent: unknown;
67
+ /** Loader zachycený jednou při vzniku exact membership identity. */
68
+ readonly lazyLoad: implementationClassifier.CapturedReactLazyLoader | undefined;
69
+ /** Current boundary-local managed-lazy presentation. */
70
+ readonly lazyStatus: OutletManagedLazyStatus;
71
+ /** Raw registry osa current membership identity. */
72
+ readonly rawRegistry: object;
73
+ /** Opaque Core registration osa current membership identity. */
74
+ readonly registrationId: string;
75
+ /** Retained local membership token current identity. */
76
+ readonly membershipToken: outletMembership.OutletMembershipToken;
77
+ /** Aktuální render/policy větev. */
78
+ readonly mode: OutletMembershipRenderMode;
79
+ /** Frozen primary event pro hidden/fallback/escalation evidenci. */
80
+ readonly primaryError: reactAdapterDiagnostics.ReactAdapterErrorEvent | undefined;
81
+ /** Generation-bound retry capability current primary failure. */
82
+ readonly retry: (() => void) | undefined;
83
+ /** Monotonická retry generation začínající nulou. */
84
+ readonly retryGeneration: number;
85
+ /** Opaque token exact retry generation. */
86
+ readonly retryToken: OutletRetryGenerationToken;
87
+ /** Monotonická subtree identita měněná při registry/membership resetu. */
88
+ readonly subtreeGeneration: number;
89
+ }
90
+
91
+ /** Mutable interní authority jednoho primary failure attemptu. */
92
+ interface OutletPrimaryFailureAttempt {
93
+ /** Sync invalidace před accepted retry nebo lifecycle cleanupem. */
94
+ authoritative: boolean;
95
+ /** Exact boundary lease bránící oživení capability v nové scope epoše. */
96
+ readonly boundaryLease: outletCommitLease.OutletCommitLease;
97
+ /** At-most-once guard celé committed primary pipeline. */
98
+ published: boolean;
99
+ /** Exact error attempt token z React/synthetic capture. */
100
+ readonly errorAttemptToken: object;
101
+ /** Exact membership token chránící identity switch. */
102
+ readonly membershipToken: outletMembership.OutletMembershipToken;
103
+ /** Public capability s vlastní at-most-once autoritou. */
104
+ retry: () => void;
105
+ /** Exact retry generation token chránící ordinary rerender. */
106
+ readonly retryToken: OutletRetryGenerationToken;
107
+ }
108
+
109
+ /** Commit-time safe channel jednoho managed-lazy attemptu. */
110
+ interface OutletManagedLazyDiagnosticChannel {
111
+ /** Opaque boundary identita přidělená před loader startem. */
112
+ readonly boundaryId: string;
113
+ /** Effective read-once sink konfigurace owning outlet generation. */
114
+ readonly configuration: adapterConfiguration.AdapterScopeConfiguration;
115
+ /** Bezpečná contribution metadata bez dat nebo implementation. */
116
+ readonly contribution: reactAdapterDiagnostics.ReadonlyContributionMetadata;
117
+ /** Exact outlet lease, jejíž retirement umlčí pozdní settlement. */
118
+ readonly outletLease: outletCommitLease.OutletCommitLease;
119
+ /** Volitelná bezpečná point metadata bez runtime capability. */
120
+ readonly point?: reactAdapterDiagnostics.ReadonlyPointMetadata;
121
+ /** Exact raw registry pouze pro live retirement gate, nikdy pro event payload. */
122
+ readonly rawRegistry: object;
123
+ /** Public retry generation původního loader attemptu. */
124
+ readonly retryGeneration: number;
125
+ /** Stabilní scope, který vlastní diagnostickou epochu. */
126
+ readonly scope: adapterScope.AdapterScopeRuntime;
127
+ /** Exact scope generation owning loader start. */
128
+ readonly scopeGeneration: adapterScope.AdapterScopeGeneration;
129
+ }
130
+
131
+ /** Props čistého contribution/loading rendereru uvnitř primary boundary. */
132
+ interface OutletMembershipRendererProps<
133
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
134
+ > {
135
+ /** Current read-once outlet callback set. */
136
+ readonly input: outletInput.CapturedOutletInput<Point>;
137
+ /** Current ready nebo loading projected seed. */
138
+ readonly seed:
139
+ | outletProjection.OutletReadyMembershipSeed<Point>
140
+ | outletProjection.OutletLoadingMembershipSeed<Point>;
141
+ }
142
+
143
+ /** Props host fallback rendereru izolovaného reporter boundary. */
144
+ interface OutletContributionFallbackRendererProps<
145
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
146
+ > {
147
+ /** Frozen public error event current primary failure. */
148
+ readonly error: reactAdapterDiagnostics.ReactAdapterErrorEvent;
149
+ /** Read-once captured fallback callback. */
150
+ readonly renderContributionError: outletInput.CapturedOutletCallback<unknown, react.ReactNode>;
151
+ /** Current membership render seed s logical placementem. */
152
+ readonly seed: outletProjection.OutletProjectedMembershipSeed<Point>;
153
+ /** Generation-bound retry capability. */
154
+ readonly retry: () => void;
155
+ }
156
+
157
+ /** Vytvoří nový render-pure opaque retry generation token. */
158
+ function createRetryGenerationToken(): OutletRetryGenerationToken {
159
+ return Object.freeze({});
160
+ }
161
+
162
+ /** Vytvoří počáteční nebo identity-reset state před renderem nové membership. */
163
+ function createMembershipBoundaryState<
164
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
165
+ >(
166
+ props: OutletMembershipBoundaryProps<Point>,
167
+ subtreeGeneration = 0,
168
+ ): OutletMembershipBoundaryState {
169
+ const seed = props.membership.seed;
170
+ return {
171
+ capturedCause: undefined,
172
+ escalationCause: undefined,
173
+ errorAttemptToken: undefined,
174
+ hasCapturedCause: false,
175
+ lazyComponent: undefined,
176
+ lazyLoad: seed.kind === "loading" ? seed.load : undefined,
177
+ lazyStatus: seed.kind === "loading" ? "loading" : "inactive",
178
+ rawRegistry: props.rawRegistry,
179
+ registrationId: props.membership.seed.registrationId,
180
+ membershipToken: props.membership.token,
181
+ mode: "rendering",
182
+ primaryError: undefined,
183
+ retry: undefined,
184
+ retryGeneration: 0,
185
+ retryToken: createRetryGenerationToken(),
186
+ subtreeGeneration,
187
+ };
188
+ }
189
+
190
+ /** Renderuje ready nebo loading větev uvnitř package class boundary. */
191
+ function OutletMembershipRenderer<
192
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
193
+ >(
194
+ props: OutletMembershipRendererProps<Point>,
195
+ ): react.ReactElement | null {
196
+ const seed = props.seed;
197
+ if (seed.kind === "loading") {
198
+ if (props.input.renderLoading === undefined) {
199
+ return null;
200
+ }
201
+ const rendered = outletInput.callCapturedOutletCallback(
202
+ props.input.renderLoading,
203
+ seed.renderState,
204
+ );
205
+ return react.createElement(react.Fragment, null, rendered);
206
+ }
207
+ if (props.input.renderContribution !== undefined) {
208
+ const rendered = outletInput.callCapturedOutletCallback(
209
+ props.input.renderContribution,
210
+ seed.renderState,
211
+ );
212
+ return react.createElement(react.Fragment, null, rendered);
213
+ }
214
+ return react.createElement(seed.renderState.component, seed.renderState.componentProps);
215
+ }
216
+
217
+ /** Volá contribution fallback uvnitř samostatné reporter class boundary. */
218
+ function OutletContributionFallbackRenderer<
219
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
220
+ >(
221
+ props: OutletContributionFallbackRendererProps<Point>,
222
+ ): react.ReactElement {
223
+ const state = Object.freeze({
224
+ ...props.seed.renderState,
225
+ error: props.error,
226
+ retry: props.retry,
227
+ });
228
+ const rendered = outletInput.callCapturedOutletCallback(
229
+ props.renderContributionError,
230
+ state,
231
+ );
232
+ return react.createElement(react.Fragment, null, rendered);
233
+ }
234
+
235
+ /** Vrátí exact synthetic cause, nebo původní classifier cause ReactAdapterErroru. */
236
+ function resolveProjectedFailureCause(error: reactAdapterError.ReactAdapterError): unknown {
237
+ return Object.hasOwn(error, "cause") ? error.cause : error;
238
+ }
239
+
240
+ /** Odvodí public phase z bezpečných details, jinak použije render. */
241
+ function resolveProjectedFailurePhase(
242
+ error: reactAdapterError.ReactAdapterError,
243
+ ): reactAdapterError.ReactAdapterErrorPhase {
244
+ const phase = error.details.phase;
245
+ return phase === "configuration"
246
+ || phase === "resolve"
247
+ || phase === "load"
248
+ || phase === "render"
249
+ || phase === "customRender"
250
+ || phase === "fallback"
251
+ || phase === "policy"
252
+ || phase === "projection"
253
+ || phase === "callback"
254
+ || phase === "lifecycle"
255
+ ? phase
256
+ : "render";
257
+ }
258
+
259
+ /** Projektuje pouze bezpečnou identitu current managed-lazy contribution. */
260
+ function createManagedLazyContributionMetadata<
261
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
262
+ >(
263
+ seed: outletProjection.OutletLoadingMembershipSeed<Point>,
264
+ ): reactAdapterDiagnostics.ReadonlyContributionMetadata {
265
+ const contribution = seed.renderState.contribution;
266
+ return Object.freeze({
267
+ registrationId: seed.registrationId,
268
+ contributionId: contribution.contributionId,
269
+ ...(contribution.contributorId === undefined
270
+ ? {}
271
+ : { contributorId: contribution.contributorId }),
272
+ ...(contribution.label === undefined ? {} : { label: contribution.label }),
273
+ ...(contribution.localName === undefined
274
+ ? {}
275
+ : { localName: contribution.localName }),
276
+ });
277
+ }
278
+
279
+ /** Ověří active live registry bez propouštění hostile state accessoru. */
280
+ function isManagedLazyRegistryActive(rawRegistry: object): boolean {
281
+ try {
282
+ return Reflect.get(rawRegistry, "state", rawRegistry) === "active";
283
+ } catch {
284
+ return false;
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Interní class error boundary jedné exact Core membership.
290
+ */
291
+ export class OutletMembershipBoundary<
292
+ Point extends reactExtensionPoint.AnyReactExtensionPoint,
293
+ > extends react.Component<
294
+ OutletMembershipBoundaryProps<Point>,
295
+ OutletMembershipBoundaryState
296
+ > {
297
+ /** Current identity/generation/presentation state. */
298
+ public override state: OutletMembershipBoundaryState;
299
+
300
+ /** Current commit-owned boundary ID lease. */
301
+ #boundaryLease: outletCommitLease.OutletCommitLease | undefined;
302
+ /** Membership token, pro který current lease vznikla. */
303
+ #boundaryLeaseToken: outletMembership.OutletMembershipToken | undefined;
304
+ /** Current mutable primary attempt authority. */
305
+ #primaryAttempt: OutletPrimaryFailureAttempt | undefined;
306
+ /** Poslední retry generation již doručená onRetry callbacku. */
307
+ #reportedRetryGeneration = 0;
308
+ /** Current resource-free nebo started managed-lazy operation. */
309
+ #lazyOperation: managedLazyGeneration.ManagedLazyGenerationOperation | undefined;
310
+ /** Membership token owning current lazy operation. */
311
+ #lazyOperationMembershipToken: outletMembership.OutletMembershipToken | undefined;
312
+ /** Retry token owning current lazy operation. */
313
+ #lazyOperationRetryToken: OutletRetryGenerationToken | undefined;
314
+ /** Zabraňuje novému attemptu během loading-error invalidace a abortu. */
315
+ #lazyStartBarrier = 0;
316
+ /** Terminální guard skutečného unmountu i Strict grace mezery. */
317
+ #unmounted = false;
318
+
319
+ /** Vytvoří resource-free initial state a operation bez loader side effectu. */
320
+ public constructor(props: OutletMembershipBoundaryProps<Point>) {
321
+ super(props);
322
+ this.state = createMembershipBoundaryState(props);
323
+ this.#synchronizeLazyOperation();
324
+ }
325
+
326
+ /** Capture descendant error bez sinku, callbacku, policy nebo Core callu. */
327
+ public static getDerivedStateFromError(cause: unknown): Partial<OutletMembershipBoundaryState> {
328
+ return {
329
+ capturedCause: cause,
330
+ errorAttemptToken: Object.freeze({}),
331
+ hasCapturedCause: true,
332
+ mode: "captured",
333
+ primaryError: undefined,
334
+ retry: undefined,
335
+ };
336
+ }
337
+
338
+ /** Resetuje celý boundary state před renderem jiné identity tuple. */
339
+ public static getDerivedStateFromProps(
340
+ props: OutletMembershipBoundaryProps<reactExtensionPoint.AnyReactExtensionPoint>,
341
+ state: OutletMembershipBoundaryState,
342
+ ): OutletMembershipBoundaryState | null {
343
+ return props.rawRegistry === state.rawRegistry
344
+ && props.membership.seed.registrationId === state.registrationId
345
+ && props.membership.token === state.membershipToken
346
+ ? null
347
+ : createMembershipBoundaryState(props, state.subtreeGeneration + 1);
348
+ }
349
+
350
+ /** Commit acquire boundary identity a případné synthetic seed failure. */
351
+ public override componentDidMount(): void {
352
+ this.#unmounted = false;
353
+ this.#synchronizeBoundaryLease();
354
+ this.#reactivatePreservedPrimaryAttempt();
355
+ const operationChanged = this.#synchronizeLazyOperation();
356
+ this.#commitProjectedFailure();
357
+ if (operationChanged) {
358
+ this.forceUpdate();
359
+ }
360
+ }
361
+
362
+ /** Synchronizuje identity switch, committed retry event a current seed failure. */
363
+ public override componentDidUpdate(
364
+ _previousProps: OutletMembershipBoundaryProps<Point>,
365
+ previousState: OutletMembershipBoundaryState,
366
+ ): void {
367
+ if (previousState.membershipToken !== this.state.membershipToken
368
+ || previousState.rawRegistry !== this.state.rawRegistry
369
+ || previousState.registrationId !== this.state.registrationId) {
370
+ this.#invalidatePrimaryAttempt();
371
+ const dispatchAbort = this.#invalidateLazyOperation();
372
+ dispatchAbort();
373
+ this.#reportedRetryGeneration = 0;
374
+ }
375
+ this.#synchronizeBoundaryLease();
376
+ this.#reactivatePreservedPrimaryAttempt();
377
+ const operationChanged = this.#synchronizeLazyOperation();
378
+ if (previousState.retryGeneration !== this.state.retryGeneration) {
379
+ this.#reportCommittedRetry();
380
+ }
381
+ this.#commitProjectedFailure();
382
+ if (operationChanged) {
383
+ this.forceUpdate();
384
+ }
385
+ }
386
+
387
+ /** Commit point primary render chyby spustí pipeline právě jednou. */
388
+ public override componentDidCatch(cause: unknown, info: react.ErrorInfo): void {
389
+ const attemptToken = this.state.errorAttemptToken;
390
+ if (!this.state.hasCapturedCause || attemptToken === undefined) {
391
+ return;
392
+ }
393
+ const phase = this.#readRenderFailurePhase();
394
+ const reactComponentStack = outletErrorPipeline.normalizeReactComponentStack(
395
+ info.componentStack,
396
+ );
397
+ if (this.state.lazyStatus !== "loading") {
398
+ this.#commitPrimaryFailure(
399
+ attemptToken,
400
+ "REACT_RENDER_FAILED",
401
+ phase,
402
+ cause,
403
+ reactComponentStack,
404
+ );
405
+ return;
406
+ }
407
+
408
+ const dispatchAbort = this.#invalidateLazyOperation();
409
+ this.#lazyStartBarrier += 1;
410
+ try {
411
+ this.#commitPrimaryFailure(
412
+ attemptToken,
413
+ "REACT_RENDER_FAILED",
414
+ phase,
415
+ cause,
416
+ reactComponentStack,
417
+ );
418
+ } finally {
419
+ try {
420
+ dispatchAbort();
421
+ } finally {
422
+ this.#lazyStartBarrier -= 1;
423
+ }
424
+ }
425
+ }
426
+
427
+ /** Synchronous invalidace před release commit-owned boundary lease. */
428
+ public override componentWillUnmount(): void {
429
+ this.#unmounted = true;
430
+ this.#invalidatePrimaryAttempt();
431
+ this.#releaseBoundaryLease();
432
+ }
433
+
434
+ /** Renderuje current membership, provisional null, fallback nebo exact escalation. */
435
+ public override render(): react.ReactNode {
436
+ if (this.state.mode === "escalating") {
437
+ throw this.state.escalationCause;
438
+ }
439
+ if (this.state.mode === "captured" || this.state.mode === "hidden") {
440
+ return null;
441
+ }
442
+ if (this.state.mode === "fallback") {
443
+ return this.#renderFallback();
444
+ }
445
+ const seed = this.props.membership.seed;
446
+ if (seed.kind === "failed") {
447
+ return null;
448
+ }
449
+ if (seed.kind === "loading" && this.state.lazyStatus === "failed") {
450
+ return null;
451
+ }
452
+ const rendered = react.createElement(OutletMembershipRenderer<Point>, {
453
+ key: `${this.state.subtreeGeneration}:${this.state.retryGeneration}`,
454
+ input: this.props.input,
455
+ seed: this.#createCurrentRenderSeed(seed),
456
+ });
457
+ const operation = this.#readCurrentLazyOperation();
458
+ return operation === undefined
459
+ ? rendered
460
+ : react.createElement(
461
+ managedLazyGeneration.ManagedLazyCommitLease,
462
+ { children: rendered, operation },
463
+ );
464
+ }
465
+
466
+ /**
467
+ * Převede loaded lazy componentu na ready seed s nejnovějším render inputem.
468
+ */
469
+ #createCurrentRenderSeed(
470
+ seed:
471
+ | outletProjection.OutletReadyMembershipSeed<Point>
472
+ | outletProjection.OutletLoadingMembershipSeed<Point>,
473
+ ):
474
+ | outletProjection.OutletReadyMembershipSeed<Point>
475
+ | outletProjection.OutletLoadingMembershipSeed<Point> {
476
+ if (seed.kind !== "loading" || this.state.lazyStatus !== "ready") {
477
+ return seed;
478
+ }
479
+ const component = this.state.lazyComponent as contributionComponent.ReactContributionComponent<
480
+ contribKitCore.ExtensionPointContext<Point>,
481
+ contribKitCore.ExtensionPointData<Point>
482
+ >;
483
+ const componentProps = Object.freeze({
484
+ context: seed.renderState.context,
485
+ contribution: seed.renderState.contribution,
486
+ placement: seed.renderState.placement,
487
+ });
488
+ return Object.freeze({
489
+ kind: "ready",
490
+ registrationId: seed.registrationId,
491
+ renderState: Object.freeze({
492
+ ...seed.renderState,
493
+ component,
494
+ componentProps,
495
+ }),
496
+ });
497
+ }
498
+
499
+ /** Vrátí operation pouze pro exact renderovanou loading generation. */
500
+ #readCurrentLazyOperation(): managedLazyGeneration.ManagedLazyGenerationOperation | undefined {
501
+ return this.state.lazyStatus === "loading"
502
+ && this.#lazyStartBarrier === 0
503
+ && this.#lazyOperationMembershipToken === this.state.membershipToken
504
+ && this.#lazyOperationRetryToken === this.state.retryToken
505
+ ? this.#lazyOperation
506
+ : undefined;
507
+ }
508
+
509
+ /**
510
+ * Vytvoří nejvýše jednu resource-free operation pro exact retry generation.
511
+ */
512
+ #synchronizeLazyOperation(): boolean {
513
+ const load = this.state.lazyLoad;
514
+ const seed = this.props.membership.seed;
515
+ const outletLease = this.props.outletLease;
516
+ if (outletLease === undefined
517
+ || this.state.lazyStatus !== "loading" || load === undefined
518
+ || seed.kind !== "loading" || this.#lazyStartBarrier > 0) {
519
+ return false;
520
+ }
521
+ if (this.#lazyOperation !== undefined
522
+ && this.#lazyOperationMembershipToken === this.state.membershipToken
523
+ && this.#lazyOperationRetryToken === this.state.retryToken) {
524
+ this.#lazyOperation.requestStartRecheck();
525
+ return false;
526
+ }
527
+
528
+ const dispatchPreviousAbort = this.#invalidateLazyOperation();
529
+ dispatchPreviousAbort();
530
+ const membershipToken = this.state.membershipToken;
531
+ const retryToken = this.state.retryToken;
532
+ const retryGeneration = this.state.retryGeneration;
533
+ const scope = this.props.scope;
534
+ const scopeGeneration = this.props.scopeGeneration;
535
+ const rawRegistry = this.props.rawRegistry;
536
+ const configuration = this.props.input.configuration;
537
+ const contribution = createManagedLazyContributionMetadata(seed);
538
+ const point = reactAdapterDiagnostics.createPointMetadata(seed.renderState.point);
539
+ let diagnosticChannel: OutletManagedLazyDiagnosticChannel | undefined;
540
+ let lifecycleFailureReported = false;
541
+ let operation: managedLazyGeneration.ManagedLazyGenerationOperation;
542
+ /** Otestuje current operation včetně committed outlet a scope lease. */
543
+ function isCurrentOperation(boundary: OutletMembershipBoundary<Point>): boolean {
544
+ return boundary.#lazyOperation === operation
545
+ && boundary.state.lazyStatus === "loading"
546
+ && boundary.#lazyStartBarrier === 0
547
+ && boundary.#isGenerationCurrent(membershipToken, retryToken);
548
+ }
549
+ operation = new managedLazyGeneration.ManagedLazyGenerationOperation(
550
+ retryGeneration,
551
+ load,
552
+ Object.freeze({
553
+ isCurrent: (): boolean => isCurrentOperation(this),
554
+ onResolved: (component: unknown): void => {
555
+ this.#publishLazyComponent(operation, membershipToken, retryToken, component);
556
+ },
557
+ onFailed: (failure: managedLazyGeneration.ManagedLazyGenerationFailure): void => {
558
+ this.#publishLazyFailure(operation, membershipToken, retryToken, failure);
559
+ },
560
+ onLate: (outcome: "resolved" | "rejected"): void => {
561
+ this.#reportLateLazyResult(operation, diagnosticChannel, outcome);
562
+ },
563
+ onLifecycleFailure: (cause: unknown): void => {
564
+ if (lifecycleFailureReported) {
565
+ return;
566
+ }
567
+ lifecycleFailureReported = true;
568
+ this.#reportLazyLifecycleFailure(diagnosticChannel, cause);
569
+ },
570
+ registerInvalidation: (
571
+ invalidate: () => managedLazyGeneration.ManagedLazyAbortDispatch,
572
+ ): contribKitCore.Unsubscribe => {
573
+ const boundaryLease = this.#boundaryLease;
574
+ if (boundaryLease !== undefined
575
+ && boundaryLease.isCurrent()
576
+ && outletLease.isCurrent()
577
+ && scope.isGenerationActive(scopeGeneration)) {
578
+ diagnosticChannel = Object.freeze({
579
+ boundaryId: boundaryLease.id,
580
+ configuration,
581
+ contribution,
582
+ outletLease,
583
+ ...(point === undefined ? {} : { point }),
584
+ rawRegistry,
585
+ retryGeneration,
586
+ scope,
587
+ scopeGeneration,
588
+ });
589
+ }
590
+ return scope.registerEpochAbortable(
591
+ scopeGeneration,
592
+ (): managedLazyGeneration.ManagedLazyAbortDispatch => {
593
+ if (this.#lazyOperation === operation) {
594
+ this.#lazyOperation = undefined;
595
+ this.#lazyOperationMembershipToken = undefined;
596
+ this.#lazyOperationRetryToken = undefined;
597
+ }
598
+ return invalidate();
599
+ },
600
+ );
601
+ },
602
+ }),
603
+ );
604
+ this.#lazyOperation = operation;
605
+ this.#lazyOperationMembershipToken = membershipToken;
606
+ this.#lazyOperationRetryToken = retryToken;
607
+ return true;
608
+ }
609
+
610
+ /** Doručí jeden safe late-result event pouze do stále vlastněného channelu. */
611
+ #reportLateLazyResult(
612
+ operation: managedLazyGeneration.ManagedLazyGenerationOperation,
613
+ channel: OutletManagedLazyDiagnosticChannel | undefined,
614
+ outcome: "resolved" | "rejected",
615
+ ): void {
616
+ if (channel === undefined
617
+ || !channel.scope.isGenerationActive(channel.scopeGeneration)
618
+ || !channel.outletLease.isCurrent()
619
+ || !isManagedLazyRegistryActive(channel.rawRegistry)
620
+ || !channel.scope.claimDiagnosticAttempt(operation.loadAttemptToken)) {
621
+ return;
622
+ }
623
+ reactAdapterDiagnostics.reportReactAdapterDiagnostic(
624
+ reactAdapterDiagnostics.createLateLazyResultDiagnostic({
625
+ boundaryId: channel.boundaryId,
626
+ contribution: channel.contribution,
627
+ outcome,
628
+ outletId: channel.outletLease.id,
629
+ ...(channel.point === undefined ? {} : { point: channel.point }),
630
+ retryGeneration: channel.retryGeneration,
631
+ }),
632
+ channel.configuration,
633
+ );
634
+ }
635
+
636
+ /** Publikuje abort/unsubscribe failure bez UI, callback nebo policy autority. */
637
+ #reportLazyLifecycleFailure(
638
+ channel: OutletManagedLazyDiagnosticChannel | undefined,
639
+ cause: unknown,
640
+ ): void {
641
+ if (channel === undefined
642
+ || !channel.scope.isGenerationActive(channel.scopeGeneration)
643
+ || !channel.outletLease.isCurrent()
644
+ || !isManagedLazyRegistryActive(channel.rawRegistry)) {
645
+ return;
646
+ }
647
+ const error = reactAdapterDiagnostics.createReactAdapterErrorEvent({
648
+ boundaryId: channel.boundaryId,
649
+ code: "REACT_CALLBACK_FAILED",
650
+ cause,
651
+ contribution: channel.contribution,
652
+ outletId: channel.outletLease.id,
653
+ phase: "lifecycle",
654
+ ...(channel.point === undefined ? {} : { point: channel.point }),
655
+ retryGeneration: channel.retryGeneration,
656
+ });
657
+ reactAdapterDiagnostics.reportReactAdapterDiagnostic(
658
+ reactAdapterDiagnostics.createErrorDiagnostic(error),
659
+ channel.configuration,
660
+ );
661
+ }
662
+
663
+ /** Publikuje validní componentu pouze do exact current loading generation. */
664
+ #publishLazyComponent(
665
+ operation: managedLazyGeneration.ManagedLazyGenerationOperation,
666
+ membershipToken: outletMembership.OutletMembershipToken,
667
+ retryToken: OutletRetryGenerationToken,
668
+ component: unknown,
669
+ ): void {
670
+ if (this.#lazyOperation !== operation
671
+ || this.state.lazyStatus !== "loading"
672
+ || !this.#isGenerationCurrent(membershipToken, retryToken)) {
673
+ return;
674
+ }
675
+ this.setState({ lazyComponent: component, lazyStatus: "ready" });
676
+ }
677
+
678
+ /** Převede current lazy failure do committed contribution error pipeline. */
679
+ #publishLazyFailure(
680
+ operation: managedLazyGeneration.ManagedLazyGenerationOperation,
681
+ membershipToken: outletMembership.OutletMembershipToken,
682
+ retryToken: OutletRetryGenerationToken,
683
+ failure: managedLazyGeneration.ManagedLazyGenerationFailure,
684
+ ): void {
685
+ if (this.#lazyOperation !== operation
686
+ || this.state.lazyStatus !== "loading"
687
+ || !this.#isGenerationCurrent(membershipToken, retryToken)) {
688
+ return;
689
+ }
690
+ const cause = Object.hasOwn(failure, "cause")
691
+ ? failure.cause
692
+ : new reactAdapterErrorRuntime.ReactAdapterError(
693
+ "REACT_POINT_IMPLEMENTATION_INVALID",
694
+ "The managed React contribution loader returned a non-component value.",
695
+ { details: { field: "loader.result", phase: "load" } },
696
+ );
697
+ const errorAttemptToken = Object.freeze({});
698
+ this.setState(
699
+ { lazyComponent: undefined, lazyStatus: "failed" },
700
+ /** Pipeline smí začít až po commitu failed presentation. */
701
+ (): void => {
702
+ if (this.#lazyOperation !== operation
703
+ || this.state.lazyStatus !== "failed"
704
+ || !this.#isGenerationCurrent(membershipToken, retryToken)) {
705
+ return;
706
+ }
707
+ this.#commitPrimaryFailure(
708
+ errorAttemptToken,
709
+ failure.code,
710
+ "load",
711
+ cause,
712
+ undefined,
713
+ );
714
+ },
715
+ );
716
+ }
717
+
718
+ /** Zneplatní current lazy operation a vrátí oddělený abort dispatch. */
719
+ #invalidateLazyOperation(): managedLazyGeneration.ManagedLazyAbortDispatch {
720
+ const operation = this.#lazyOperation;
721
+ this.#lazyOperation = undefined;
722
+ this.#lazyOperationMembershipToken = undefined;
723
+ this.#lazyOperationRetryToken = undefined;
724
+ return operation?.invalidate() ?? managedLazyGeneration.skipManagedLazyAbortDispatch;
725
+ }
726
+
727
+ /** Ověří a případně obnoví commit lease current membership tokenu. */
728
+ #synchronizeBoundaryLease(): void {
729
+ const membershipToken = this.state.membershipToken;
730
+ if (this.props.outletLease?.isCurrent() !== true) {
731
+ this.#releaseBoundaryLease();
732
+ return;
733
+ }
734
+ if (this.#boundaryLeaseToken === membershipToken
735
+ && this.#boundaryLease?.isCurrent() === true) {
736
+ return;
737
+ }
738
+ this.#releaseBoundaryLease();
739
+ this.#boundaryLease = this.props.scope.acquireCommitLease(
740
+ this.props.scopeGeneration,
741
+ "boundary",
742
+ membershipToken,
743
+ );
744
+ this.#boundaryLeaseToken = membershipToken;
745
+ }
746
+
747
+ /** Idempotentně release boundary lease bez změny Core registry. */
748
+ #releaseBoundaryLease(): void {
749
+ this.#boundaryLease?.release();
750
+ this.#boundaryLease = undefined;
751
+ this.#boundaryLeaseToken = undefined;
752
+ }
753
+
754
+ /** Ověří current committed membership, retry generation, outlet i scope lease. */
755
+ #isGenerationCurrent(
756
+ membershipToken: outletMembership.OutletMembershipToken,
757
+ retryToken: OutletRetryGenerationToken,
758
+ ): boolean {
759
+ return !this.#unmounted
760
+ && this.state.membershipToken === membershipToken
761
+ && this.state.retryToken === retryToken
762
+ && this.props.rawRegistry === this.state.rawRegistry
763
+ && this.props.membership.token === membershipToken
764
+ && this.props.membership.seed.registrationId === this.state.registrationId
765
+ && this.#boundaryLeaseToken === membershipToken
766
+ && this.#boundaryLease?.isCurrent() === true
767
+ && this.props.outletLease?.isCurrent() === true;
768
+ }
769
+
770
+ /** Ověří celý primary attempt včetně sync retry invalidace. */
771
+ #isPrimaryAttemptCurrent(attempt: OutletPrimaryFailureAttempt): boolean {
772
+ return attempt.authoritative
773
+ && this.#primaryAttempt === attempt
774
+ && this.#boundaryLease === attempt.boundaryLease
775
+ && attempt.boundaryLease.isCurrent()
776
+ && this.#isGenerationCurrent(attempt.membershipToken, attempt.retryToken);
777
+ }
778
+
779
+ /** Vytvoří retry capability svázanou s current boundary lease a UI generation. */
780
+ #createPrimaryAttempt(
781
+ errorAttemptToken: object,
782
+ boundaryLease: outletCommitLease.OutletCommitLease,
783
+ ): OutletPrimaryFailureAttempt {
784
+ const attempt: OutletPrimaryFailureAttempt = {
785
+ authoritative: true,
786
+ boundaryLease,
787
+ published: false,
788
+ errorAttemptToken,
789
+ membershipToken: this.state.membershipToken,
790
+ retry: (): void => {},
791
+ retryToken: this.state.retryToken,
792
+ };
793
+ const boundary = this;
794
+ /** Přijme právě první current retry call dané primary capability. */
795
+ function retry(): void {
796
+ boundary.#acceptRetry(attempt);
797
+ }
798
+ attempt.retry = Object.freeze(retry);
799
+ return attempt;
800
+ }
801
+
802
+ /** Zneplatní primary capability dříve než začne další lifecycle práce. */
803
+ #invalidatePrimaryAttempt(): void {
804
+ if (this.#primaryAttempt !== undefined) {
805
+ this.#primaryAttempt.authoritative = false;
806
+ this.#primaryAttempt = undefined;
807
+ }
808
+ }
809
+
810
+ /**
811
+ * Naváže zachovanou failed presentation na novou Activity epochu bez replaye pipeline.
812
+ */
813
+ #reactivatePreservedPrimaryAttempt(): void {
814
+ if (this.state.primaryError === undefined
815
+ || this.state.retry === undefined
816
+ || (this.state.mode !== "fallback" && this.state.mode !== "hidden")) {
817
+ return;
818
+ }
819
+ const currentAttempt = this.#primaryAttempt;
820
+ if (currentAttempt !== undefined && this.#isPrimaryAttemptCurrent(currentAttempt)) {
821
+ return;
822
+ }
823
+ this.#invalidatePrimaryAttempt();
824
+ const boundaryLease = this.#boundaryLease;
825
+ if (boundaryLease === undefined
826
+ || !this.#isGenerationCurrent(this.state.membershipToken, this.state.retryToken)) {
827
+ return;
828
+ }
829
+ const attempt = this.#createPrimaryAttempt(Object.freeze({}), boundaryLease);
830
+ attempt.published = true;
831
+ this.#primaryAttempt = attempt;
832
+ this.setState({ retry: attempt.retry });
833
+ }
834
+
835
+ /** Převede current failed projection na committed primary pipeline. */
836
+ #commitProjectedFailure(): void {
837
+ const seed = this.props.membership.seed;
838
+ if (seed.kind !== "failed" || this.state.mode !== "rendering") {
839
+ return;
840
+ }
841
+ this.#commitPrimaryFailure(
842
+ Object.freeze({}),
843
+ seed.error.code,
844
+ resolveProjectedFailurePhase(seed.error),
845
+ resolveProjectedFailureCause(seed.error),
846
+ undefined,
847
+ );
848
+ }
849
+
850
+ /** Spustí at-most-once pipeline jednoho exact membership/error attemptu. */
851
+ #commitPrimaryFailure(
852
+ errorAttemptToken: object,
853
+ code: reactAdapterError.ReactAdapterErrorCode,
854
+ phase: reactAdapterError.ReactAdapterErrorPhase,
855
+ cause: unknown,
856
+ reactComponentStack: string | undefined,
857
+ ): void {
858
+ this.#synchronizeBoundaryLease();
859
+ const membershipToken = this.state.membershipToken;
860
+ const retryToken = this.state.retryToken;
861
+ if (!this.#isGenerationCurrent(membershipToken, retryToken)) {
862
+ return;
863
+ }
864
+ if (this.#primaryAttempt?.errorAttemptToken === errorAttemptToken) {
865
+ return;
866
+ }
867
+ this.#invalidatePrimaryAttempt();
868
+ const lease = this.#boundaryLease;
869
+ const outletLease = this.props.outletLease;
870
+ if (lease === undefined || outletLease === undefined) {
871
+ return;
872
+ }
873
+ const attempt = this.#createPrimaryAttempt(errorAttemptToken, lease);
874
+ this.#primaryAttempt = attempt;
875
+ if (!this.props.scope.claimDiagnosticAttempt(errorAttemptToken)) {
876
+ attempt.authoritative = false;
877
+ return;
878
+ }
879
+ attempt.published = true;
880
+ const seed = this.props.membership.seed;
881
+ const decision = outletErrorPipeline.runOutletPrimaryErrorPipeline({
882
+ boundaryId: lease.id,
883
+ code,
884
+ configuration: this.props.input.configuration,
885
+ context: seed.renderState.context,
886
+ contribution: seed.renderState.contribution,
887
+ cause,
888
+ hasFallback: this.props.input.renderContributionError !== undefined,
889
+ isolateErrors: this.props.input.isolateErrors,
890
+ isCurrent: (): boolean => this.#isPrimaryAttemptCurrent(attempt),
891
+ onError: this.props.input.onError as outletInput.CapturedOutletCallback<
892
+ outletErrorPipeline.OutletContributionErrorEmission,
893
+ unknown
894
+ > | undefined,
895
+ outletId: outletLease.id,
896
+ phase,
897
+ point: seed.renderState.point,
898
+ ...(reactComponentStack === undefined ? {} : { reactComponentStack }),
899
+ registrationId: seed.registrationId,
900
+ retry: attempt.retry,
901
+ retryGeneration: this.state.retryGeneration,
902
+ });
903
+ if (decision.kind === "stale" || !this.#isPrimaryAttemptCurrent(attempt)) {
904
+ return;
905
+ }
906
+ if (decision.kind === "hide") {
907
+ this.setState({ mode: "hidden", primaryError: decision.error, retry: attempt.retry });
908
+ return;
909
+ }
910
+ if (decision.kind === "renderFallback") {
911
+ this.setState({
912
+ mode: "fallback",
913
+ primaryError: decision.error,
914
+ retry: attempt.retry,
915
+ });
916
+ return;
917
+ }
918
+ this.setState({
919
+ escalationCause: decision.cause,
920
+ mode: "escalating",
921
+ primaryError: decision.error,
922
+ retry: attempt.retry,
923
+ });
924
+ }
925
+
926
+ /** Sync accepted retry invaliduje starý attempt a naplánuje novou subtree generation. */
927
+ #acceptRetry(attempt: OutletPrimaryFailureAttempt): void {
928
+ if (!this.#isPrimaryAttemptCurrent(attempt)) {
929
+ return;
930
+ }
931
+ attempt.authoritative = false;
932
+ this.#primaryAttempt = undefined;
933
+ const dispatchAbort = this.#invalidateLazyOperation();
934
+ dispatchAbort();
935
+ this.setState((state): Pick<
936
+ OutletMembershipBoundaryState,
937
+ | "capturedCause"
938
+ | "escalationCause"
939
+ | "errorAttemptToken"
940
+ | "hasCapturedCause"
941
+ | "lazyComponent"
942
+ | "lazyStatus"
943
+ | "mode"
944
+ | "primaryError"
945
+ | "retry"
946
+ | "retryGeneration"
947
+ | "retryToken"
948
+ > => ({
949
+ capturedCause: undefined,
950
+ escalationCause: undefined,
951
+ errorAttemptToken: undefined,
952
+ hasCapturedCause: false,
953
+ lazyComponent: undefined,
954
+ lazyStatus: state.lazyLoad === undefined ? "inactive" : "loading",
955
+ mode: "rendering",
956
+ primaryError: undefined,
957
+ retry: undefined,
958
+ retryGeneration: state.retryGeneration + 1,
959
+ retryToken: createRetryGenerationToken(),
960
+ }));
961
+ }
962
+
963
+ /** Doručí onRetry až po commitu nové current generation. */
964
+ #reportCommittedRetry(): void {
965
+ if (this.state.retryGeneration <= this.#reportedRetryGeneration) {
966
+ return;
967
+ }
968
+ this.#reportedRetryGeneration = this.state.retryGeneration;
969
+ const lease = this.#boundaryLease;
970
+ const outletLease = this.props.outletLease;
971
+ const membershipToken = this.state.membershipToken;
972
+ const retryToken = this.state.retryToken;
973
+ if (lease === undefined
974
+ || outletLease === undefined
975
+ || !this.#isGenerationCurrent(membershipToken, retryToken)) {
976
+ return;
977
+ }
978
+ const seed = this.props.membership.seed;
979
+ outletErrorPipeline.dispatchOutletRetryCallback({
980
+ boundaryId: lease.id,
981
+ configuration: this.props.input.configuration,
982
+ context: seed.renderState.context,
983
+ contribution: seed.renderState.contribution,
984
+ isCurrent: (): boolean => this.#isGenerationCurrent(membershipToken, retryToken),
985
+ onRetry: this.props.input.onRetry as outletInput.CapturedOutletCallback<
986
+ outletErrorPipeline.OutletRetryEvent,
987
+ unknown
988
+ > | undefined,
989
+ outletId: outletLease.id,
990
+ point: seed.renderState.point,
991
+ registrationId: seed.registrationId,
992
+ retryGeneration: this.state.retryGeneration,
993
+ });
994
+ }
995
+
996
+ /** Odliší default render od custom ready/loading rendereru. */
997
+ #readRenderFailurePhase(): "render" | "customRender" {
998
+ if (this.props.membership.seed.kind === "loading"
999
+ && this.state.lazyStatus !== "ready") {
1000
+ return this.props.input.renderLoading === undefined ? "render" : "customRender";
1001
+ }
1002
+ return this.props.input.renderContribution === undefined ? "render" : "customRender";
1003
+ }
1004
+
1005
+ /** Renderuje current fallback pod sink-only reporter boundary. */
1006
+ #renderFallback(): react.ReactElement | null {
1007
+ const renderContributionError = this.props.input.renderContributionError;
1008
+ const error = this.state.primaryError;
1009
+ const retry = this.state.retry;
1010
+ const lease = this.#boundaryLease;
1011
+ const outletLease = this.props.outletLease;
1012
+ if (renderContributionError === undefined
1013
+ || error === undefined
1014
+ || retry === undefined
1015
+ || lease === undefined
1016
+ || outletLease === undefined) {
1017
+ return null;
1018
+ }
1019
+ const seed = this.props.membership.seed;
1020
+ const membershipToken = this.state.membershipToken;
1021
+ const retryToken = this.state.retryToken;
1022
+ const reporterInput = {
1023
+ boundaryId: lease.id,
1024
+ configuration: this.props.input.configuration,
1025
+ context: seed.renderState.context,
1026
+ contribution: seed.renderState.contribution,
1027
+ isCurrent: (): boolean => this.#isGenerationCurrent(membershipToken, retryToken),
1028
+ outletId: outletLease.id,
1029
+ point: seed.renderState.point,
1030
+ registrationId: seed.registrationId,
1031
+ retryGeneration: this.state.retryGeneration,
1032
+ };
1033
+ const children = react.createElement(OutletContributionFallbackRenderer<Point>, {
1034
+ error,
1035
+ renderContributionError,
1036
+ retry,
1037
+ seed,
1038
+ });
1039
+ return react.createElement(
1040
+ outletReporterBoundary.OutletReporterBoundary<Point>,
1041
+ {
1042
+ children,
1043
+ errorInput: reporterInput,
1044
+ generationToken: retryToken,
1045
+ },
1046
+ );
1047
+ }
1048
+ }