@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,500 @@
1
+ import type * as contribKitCore from "@primafuture/contrib-kit-core";
2
+
3
+ import * as adapterConfiguration from "./adapter-configuration.js";
4
+ import * as adapterRegistryBridge from "./adapter-registry-bridge.js";
5
+ import * as adapterRegistryProtocol from "./adapter-registry-protocol.js";
6
+ import * as outletCommitLease from "./outlet-commit-lease.js";
7
+ import * as reactAdapterError from "../react-adapter-error.js";
8
+
9
+ /** Deterministický microtask seam používaný lifecycle grace periodou. */
10
+ export type AdapterScopeMicrotaskScheduler = (callback: () => void) => void;
11
+
12
+ /** Best-effort seam pro interní lifecycle diagnostiku. */
13
+ export type AdapterScopeLifecycleReporter = (
14
+ error: reactAdapterError.ReactAdapterError,
15
+ ) => void;
16
+
17
+ /** Idempotentní fyzický cleanup spuštěný až po zneplatnění celé scope epochy. */
18
+ export type AdapterScopeAbortDispatch = () => void;
19
+
20
+ /** Synchronní invalidace jednoho epoch-owned abortable resource. */
21
+ export type AdapterScopeAbortableInvalidation = () => AdapterScopeAbortDispatch;
22
+
23
+ /** Pure konfigurace jedné provider generation bez resource ownershipu. */
24
+ export interface AdapterScopeGeneration {
25
+ /** Default registry protocol provideru; explicitní hook registry jej nepřepisuje. */
26
+ readonly defaultProtocol: adapterRegistryProtocol.AdapterRegistryProtocolSnapshot;
27
+ /** Efektivní nearest-provider konfigurace všech tří nezávislých os. */
28
+ readonly configuration: adapterConfiguration.AdapterScopeConfiguration;
29
+ }
30
+
31
+ /** Interní external-store kontrakt připravený pro budoucí React hook. */
32
+ export interface AdapterExternalStoreBinding {
33
+ /** Commit-time acquire point consumer membership. */
34
+ readonly subscribe: (
35
+ listener: adapterRegistryBridge.AdapterExternalStoreListener,
36
+ ) => contribKitCore.Unsubscribe;
37
+ /** Pure client snapshot selector bez resource creation. */
38
+ readonly getSnapshot: () => adapterRegistryBridge.AdapterExternalStoreSnapshot;
39
+ /** Package-constant server/hydration snapshot selector. */
40
+ readonly getServerSnapshot: () => typeof adapterRegistryBridge.ADAPTER_SERVER_SNAPSHOT;
41
+ /** První bridge fault pro budoucí render-time error projection. */
42
+ readonly readFault: () => reactAdapterError.ReactAdapterError | undefined;
43
+ /** Poslední známý committed registry lifecycle stav. */
44
+ readonly readRegistryState: () => contribKitCore.ExtensionRegistryState;
45
+ }
46
+
47
+ /** Volitelné interní host seams bez veřejného package kontraktu. */
48
+ export interface AdapterScopeRuntimeOptions {
49
+ /** Vlastní deterministický scheduler pro lifecycle testy. */
50
+ readonly scheduleMicrotask?: AdapterScopeMicrotaskScheduler;
51
+ /** Bezpečný lifecycle reporter; jeho failure se vždy pohltí. */
52
+ readonly reportLifecycleFailure?: AdapterScopeLifecycleReporter;
53
+ }
54
+
55
+ /** Stav jedné monotonické committed scope epochy. */
56
+ type AdapterScopeEpochState = "active" | "grace" | "retired";
57
+
58
+ /** Resource ownership oddělený od stabilní provider scope identity. */
59
+ interface AdapterScopeEpoch {
60
+ /** Monotonická identita bez veřejného formátového kontraktu. */
61
+ readonly epoch: number;
62
+ /** Pure provider generation, kterou epocha materializuje. */
63
+ readonly generation: AdapterScopeGeneration;
64
+ /** Nejvýše jeden bridge pro každou exact raw registry referenci. */
65
+ readonly bridges: Map<object, adapterRegistryBridge.AdapterRegistryBridge>;
66
+ /** Pending abortable resources, které musí být stale před prvním abortem. */
67
+ readonly abortables: Set<AdapterScopeAbortableRecord>;
68
+ /** Počet aktivních provider owner leases. */
69
+ ownerCount: number;
70
+ /** Current lifecycle stav epochy. */
71
+ state: AdapterScopeEpochState;
72
+ /** Token rušící stale grace finalizer. */
73
+ finalizeToken: number;
74
+ }
75
+
76
+ /** Jedna odpojitelná invalidace vlastněná přesnou resource epochou. */
77
+ interface AdapterScopeAbortableRecord {
78
+ /** False po explicitním odpojení nebo epoch retirementu. */
79
+ active: boolean;
80
+ /** Vrátí fyzický abort až po synchronním odstranění resource autority. */
81
+ readonly invalidate: AdapterScopeAbortableInvalidation;
82
+ }
83
+
84
+ /**
85
+ * Použije platformní microtask bez importu Node nebo DOM ambient API.
86
+ */
87
+ function schedulePlatformMicrotask(callback: () => void): void {
88
+ queueMicrotask(callback);
89
+ }
90
+
91
+ /**
92
+ * Vytvoří stabilní lifecycle chybu bez raw registry nebo config callbacků.
93
+ */
94
+ function createStaleScopeError(): reactAdapterError.ReactAdapterError {
95
+ return new reactAdapterError.ReactAdapterError(
96
+ "REACT_ADAPTER_DISPOSED",
97
+ "The React adapter scope epoch is no longer active.",
98
+ { details: { field: "scope.epoch", phase: "lifecycle" } },
99
+ );
100
+ }
101
+
102
+ /**
103
+ * Pure factory provider generation; resource vzniká až committed acquire cestou.
104
+ */
105
+ export function createAdapterScopeGeneration(
106
+ defaultProtocol: adapterRegistryProtocol.AdapterRegistryProtocolSnapshot,
107
+ configuration: adapterConfiguration.AdapterScopeConfiguration,
108
+ ): AdapterScopeGeneration {
109
+ return Object.freeze({ defaultProtocol, configuration });
110
+ }
111
+
112
+ /**
113
+ * Porovná generation podle raw host capabilities, nikoli nových wrapper referencí.
114
+ */
115
+ export function isSameAdapterScopeGeneration(
116
+ left: AdapterScopeGeneration,
117
+ right: AdapterScopeGeneration,
118
+ ): boolean {
119
+ return left.defaultProtocol.rawRegistry === right.defaultProtocol.rawRegistry
120
+ && left.defaultProtocol.registryId === right.defaultProtocol.registryId
121
+ && adapterConfiguration.isSameAdapterScopeConfiguration(
122
+ left.configuration,
123
+ right.configuration,
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Stabilní provider-scope identity s oddělenými, monotonickými resource epochami.
129
+ */
130
+ export class AdapterScopeRuntime {
131
+ /** Read-once scheduler používaný všemi epochami scope. */
132
+ readonly #scheduleMicrotask: AdapterScopeMicrotaskScheduler;
133
+ /** Read-once best-effort lifecycle reporter. */
134
+ readonly #reportLifecycleFailure: AdapterScopeLifecycleReporter | undefined;
135
+ /** Poslední monotonická epoch identity. */
136
+ #nextEpoch = 0;
137
+ /** Právě aktivní nebo Strict-grace resource epocha. */
138
+ #currentEpoch: AdapterScopeEpoch | undefined;
139
+ /** Opaque committed attempty již doručené diagnostickému sinku. */
140
+ readonly #reportedDiagnosticAttempts = new WeakSet<object>();
141
+ /** Scope-local committed owner identities bez process-global historie. */
142
+ readonly #commitLeases: outletCommitLease.OutletCommitLeaseRegistry;
143
+
144
+ /** Vytvoří resource-free scope; žádný Core read ani subscribe zde nevzniká. */
145
+ public constructor(options: AdapterScopeRuntimeOptions = {}) {
146
+ this.#scheduleMicrotask = options.scheduleMicrotask ?? schedulePlatformMicrotask;
147
+ this.#reportLifecycleFailure = options.reportLifecycleFailure;
148
+ this.#commitLeases = new outletCommitLease.OutletCommitLeaseRegistry(
149
+ (callback: () => void): void => {
150
+ this.#schedule(callback);
151
+ },
152
+ );
153
+ }
154
+
155
+ /** Vrátí current monotonické číslo pouze pro deterministickou interní evidenci. */
156
+ public readCurrentEpoch(): number | undefined {
157
+ return this.#currentEpoch?.epoch;
158
+ }
159
+
160
+ /** Vrátí current pure provider generation bez její aktivace. */
161
+ public readCurrentGeneration(): AdapterScopeGeneration | undefined {
162
+ return this.#currentEpoch?.generation;
163
+ }
164
+
165
+ /** Ověří, že přesná generation právě vlastní aktivní committed epochu. */
166
+ public isGenerationActive(generation: AdapterScopeGeneration): boolean {
167
+ const current = this.#currentEpoch;
168
+ return current !== undefined
169
+ && current.state === "active"
170
+ && isSameAdapterScopeGeneration(current.generation, generation);
171
+ }
172
+
173
+ /** Atomicky přijme první committed diagnostiku jednoho opaque attempt tokenu. */
174
+ public claimDiagnosticAttempt(token: object): boolean {
175
+ if (this.#reportedDiagnosticAttempts.has(token)) {
176
+ return false;
177
+ }
178
+ this.#reportedDiagnosticAttempts.add(token);
179
+ return true;
180
+ }
181
+
182
+ /** Vrátí počet scope-local owner records pouze pro interní lifecycle důkaz. */
183
+ public readRetainedCommitOwnerCount(): number {
184
+ return this.#commitLeases.readRetainedOwnerCount();
185
+ }
186
+
187
+ /**
188
+ * Commit-time acquire outlet nebo boundary identity v exact current epoše.
189
+ */
190
+ public acquireCommitLease(
191
+ generation: AdapterScopeGeneration,
192
+ kind: outletCommitLease.OutletCommitOwnerKind,
193
+ token: object,
194
+ ): outletCommitLease.OutletCommitLease {
195
+ const epoch = this.#acquireEpoch(generation);
196
+ return this.#commitLeases.acquire(
197
+ epoch.epoch,
198
+ kind,
199
+ token,
200
+ (epochNumber: number): boolean => {
201
+ return this.#currentEpoch === epoch
202
+ && epoch.epoch === epochNumber
203
+ && epoch.state === "active"
204
+ && isSameAdapterScopeGeneration(epoch.generation, generation);
205
+ },
206
+ );
207
+ }
208
+
209
+ /**
210
+ * Commit-time owner acquire. Strict reacquire stejné generation zachová epochu.
211
+ */
212
+ public acquireOwner(generation: AdapterScopeGeneration): contribKitCore.Unsubscribe {
213
+ const epoch = this.#acquireEpoch(generation);
214
+ epoch.ownerCount += 1;
215
+ let active = true;
216
+ const scope = this;
217
+ /** Idempotentně uvolní právě jednu provider owner lease. */
218
+ function releaseOwner(): void {
219
+ if (!active) {
220
+ return;
221
+ }
222
+ active = false;
223
+ epoch.ownerCount -= 1;
224
+ if (epoch.ownerCount === 0 && scope.#currentEpoch === epoch) {
225
+ scope.#beginEpochGrace(epoch);
226
+ }
227
+ }
228
+
229
+ return releaseOwner;
230
+ }
231
+
232
+ /**
233
+ * Připojí committed abortable resource k právě existující scope epoše.
234
+ *
235
+ * Registrace nikdy neaktivuje novou epochu. Pokud owning epocha již zmizela,
236
+ * resource se okamžitě zneplatní a uklidí bez možnosti pozdějšího startu.
237
+ */
238
+ public registerEpochAbortable(
239
+ generation: AdapterScopeGeneration,
240
+ invalidate: AdapterScopeAbortableInvalidation,
241
+ ): contribKitCore.Unsubscribe {
242
+ const epoch = this.#currentEpoch;
243
+ if (epoch === undefined
244
+ || epoch.state === "retired"
245
+ || !isSameAdapterScopeGeneration(epoch.generation, generation)) {
246
+ this.#runAbortDispatch(this.#callAbortableInvalidation(invalidate));
247
+ return (): void => {};
248
+ }
249
+ const owningEpoch = epoch;
250
+
251
+ const record: AdapterScopeAbortableRecord = { active: true, invalidate };
252
+ owningEpoch.abortables.add(record);
253
+ let attached = true;
254
+ /** Odpojí settled nebo lokálně invalidovaný resource bez druhého cleanupu. */
255
+ function unregisterEpochAbortable(): void {
256
+ if (!attached) {
257
+ return;
258
+ }
259
+ attached = false;
260
+ record.active = false;
261
+ owningEpoch.abortables.delete(record);
262
+ }
263
+ return unregisterEpochAbortable;
264
+ }
265
+
266
+ /**
267
+ * Vytvoří pure external-store closures; žádný bridge ani cell zatím nevzniká.
268
+ */
269
+ public createExternalStore(
270
+ generation: AdapterScopeGeneration,
271
+ protocol: adapterRegistryProtocol.AdapterRegistryProtocolSnapshot,
272
+ point: contribKitCore.AnyExtensionPoint,
273
+ ): AdapterExternalStoreBinding {
274
+ const scope = this;
275
+ /** Najde bridge pouze v exact current generation bez cache mutace. */
276
+ function peekBridge(): adapterRegistryBridge.AdapterRegistryBridge | undefined {
277
+ const epoch = scope.#currentEpoch;
278
+ if (epoch === undefined
279
+ || epoch.state === "retired"
280
+ || !isSameAdapterScopeGeneration(epoch.generation, generation)) {
281
+ return undefined;
282
+ }
283
+ return epoch.bridges.get(protocol.rawRegistry);
284
+ }
285
+
286
+ return Object.freeze({
287
+ /** Commit-time scope a bridge acquire. */
288
+ subscribe(listener: adapterRegistryBridge.AdapterExternalStoreListener): contribKitCore.Unsubscribe {
289
+ if (typeof listener !== "function") {
290
+ throw new reactAdapterError.ReactAdapterError(
291
+ "REACT_INVALID_ARGUMENT",
292
+ "External-store listener must be callable.",
293
+ { details: { field: "listener", phase: "lifecycle" } },
294
+ );
295
+ }
296
+ const epoch = scope.#acquireEpoch(generation);
297
+ const bridge = scope.#getOrCreateBridge(epoch, protocol);
298
+ return bridge.subscribe(point, listener);
299
+ },
300
+ /** Pure committed-cell lookup s global pre-subscribe fallbackem. */
301
+ getSnapshot(): adapterRegistryBridge.AdapterExternalStoreSnapshot {
302
+ const token = peekBridge()?.peekSnapshot(point);
303
+ return token ?? adapterRegistryProtocol.createAdapterRegistrySnapshotToken(protocol);
304
+ },
305
+ /** Constant SSR/hydration sentinel bez request-local dat. */
306
+ getServerSnapshot(): typeof adapterRegistryBridge.ADAPTER_SERVER_SNAPSHOT {
307
+ return adapterRegistryBridge.ADAPTER_SERVER_SNAPSHOT;
308
+ },
309
+ /** Pure fault lookup pro budoucí hook error mapping. */
310
+ readFault(): reactAdapterError.ReactAdapterError | undefined {
311
+ return peekBridge()?.readFault();
312
+ },
313
+ /** Pure committed bridge state nebo initial protocol stav. */
314
+ readRegistryState(): contribKitCore.ExtensionRegistryState {
315
+ return peekBridge()?.readRegistryState() ?? protocol.initialState;
316
+ },
317
+ });
318
+ }
319
+
320
+ /** Aktivuje novou epochu nebo zruší Strict grace té current. */
321
+ #acquireEpoch(generation: AdapterScopeGeneration): AdapterScopeEpoch {
322
+ const current = this.#currentEpoch;
323
+ if (current !== undefined
324
+ && current.state !== "retired"
325
+ && isSameAdapterScopeGeneration(current.generation, generation)) {
326
+ if (current.state === "grace") {
327
+ current.finalizeToken += 1;
328
+ current.state = "active";
329
+ for (const bridge of current.bridges.values()) {
330
+ bridge.reactivateEpoch();
331
+ }
332
+ }
333
+ return current;
334
+ }
335
+
336
+ if (current !== undefined && current.state !== "retired") {
337
+ this.#retireEpoch(current);
338
+ }
339
+
340
+ this.#nextEpoch += 1;
341
+ const created: AdapterScopeEpoch = {
342
+ epoch: this.#nextEpoch,
343
+ generation,
344
+ bridges: new Map(),
345
+ abortables: new Set(),
346
+ ownerCount: 0,
347
+ state: "active",
348
+ finalizeToken: 0,
349
+ };
350
+ this.#currentEpoch = created;
351
+ return created;
352
+ }
353
+
354
+ /** Vytvoří nejvýše jeden bridge pro exact epoch + raw registry dvojici. */
355
+ #getOrCreateBridge(
356
+ epoch: AdapterScopeEpoch,
357
+ protocol: adapterRegistryProtocol.AdapterRegistryProtocolSnapshot,
358
+ ): adapterRegistryBridge.AdapterRegistryBridge {
359
+ const existing = epoch.bridges.get(protocol.rawRegistry);
360
+ if (existing !== undefined) {
361
+ return existing;
362
+ }
363
+
364
+ let created: adapterRegistryBridge.AdapterRegistryBridge;
365
+ created = new adapterRegistryBridge.AdapterRegistryBridge(protocol, {
366
+ checkpoint: (): void => {
367
+ if (this.#currentEpoch !== epoch || epoch.state !== "active") {
368
+ throw createStaleScopeError();
369
+ }
370
+ },
371
+ canFinalizeDetach: (): boolean => {
372
+ return this.#currentEpoch === epoch && epoch.state === "active";
373
+ },
374
+ scheduleMicrotask: this.#scheduleMicrotask,
375
+ reportLifecycleFailure: (error: reactAdapterError.ReactAdapterError): void => {
376
+ this.#reportFailure(error);
377
+ },
378
+ onDetached: (bridge: adapterRegistryBridge.AdapterRegistryBridge): void => {
379
+ if (epoch.bridges.get(protocol.rawRegistry) === bridge) {
380
+ epoch.bridges.delete(protocol.rawRegistry);
381
+ }
382
+ },
383
+ });
384
+ epoch.bridges.set(protocol.rawRegistry, created);
385
+ return created;
386
+ }
387
+
388
+ /** Synchronně invaliduje epochu a poté naplánuje Strict-grace finalitu. */
389
+ #beginEpochGrace(epoch: AdapterScopeEpoch): void {
390
+ if (epoch.state !== "active") {
391
+ return;
392
+ }
393
+ epoch.state = "grace";
394
+ epoch.finalizeToken += 1;
395
+ const token = epoch.finalizeToken;
396
+ this.#commitLeases.invalidateEpoch(epoch.epoch);
397
+ for (const bridge of epoch.bridges.values()) {
398
+ bridge.prepareEpochDeactivation();
399
+ }
400
+
401
+ this.#schedule((): void => {
402
+ if (this.#currentEpoch !== epoch
403
+ || epoch.state !== "grace"
404
+ || token !== epoch.finalizeToken) {
405
+ return;
406
+ }
407
+ this.#retireEpoch(epoch);
408
+ });
409
+ }
410
+
411
+ /** Terminálně označí epochu stale před prvním fyzickým unsubscribe. */
412
+ #retireEpoch(epoch: AdapterScopeEpoch): void {
413
+ if (epoch.state === "retired") {
414
+ return;
415
+ }
416
+ epoch.state = "retired";
417
+ epoch.finalizeToken += 1;
418
+ if (this.#currentEpoch === epoch) {
419
+ this.#currentEpoch = undefined;
420
+ }
421
+ this.#commitLeases.retireEpoch(epoch.epoch);
422
+ const abortDispatches: AdapterScopeAbortDispatch[] = [];
423
+ for (const record of [...epoch.abortables]) {
424
+ if (!record.active) {
425
+ continue;
426
+ }
427
+ record.active = false;
428
+ abortDispatches.push(this.#callAbortableInvalidation(record.invalidate));
429
+ }
430
+ epoch.abortables.clear();
431
+ for (const bridge of [...epoch.bridges.values()]) {
432
+ bridge.forceDetach();
433
+ }
434
+ epoch.bridges.clear();
435
+ for (const dispatchAbort of abortDispatches) {
436
+ this.#runAbortDispatch(dispatchAbort);
437
+ }
438
+ }
439
+
440
+ /** Izoluje vadný resource invalidator a zachová retirement ostatních resources. */
441
+ #callAbortableInvalidation(
442
+ invalidate: AdapterScopeAbortableInvalidation,
443
+ ): AdapterScopeAbortDispatch {
444
+ try {
445
+ return invalidate();
446
+ } catch (cause: unknown) {
447
+ this.#reportFailure(new reactAdapterError.ReactAdapterError(
448
+ "REACT_CALLBACK_FAILED",
449
+ "A React adapter lifecycle invalidation callback failed.",
450
+ {
451
+ cause,
452
+ details: { field: "scope.abortable.invalidate", phase: "lifecycle" },
453
+ },
454
+ ));
455
+ return (): void => {};
456
+ }
457
+ }
458
+
459
+ /** Spustí fyzický abort bez možnosti přepsat scope retirement. */
460
+ #runAbortDispatch(dispatchAbort: AdapterScopeAbortDispatch): void {
461
+ try {
462
+ dispatchAbort();
463
+ } catch (cause: unknown) {
464
+ this.#reportFailure(new reactAdapterError.ReactAdapterError(
465
+ "REACT_CALLBACK_FAILED",
466
+ "A React adapter lifecycle cleanup callback failed.",
467
+ {
468
+ cause,
469
+ details: { field: "scope.abortable.dispatch", phase: "lifecycle" },
470
+ },
471
+ ));
472
+ }
473
+ }
474
+
475
+ /** Scheduler failure dokončí lifecycle synchronně a pouze diagnostikuje seam. */
476
+ #schedule(callback: () => void): void {
477
+ try {
478
+ this.#scheduleMicrotask(callback);
479
+ } catch (cause: unknown) {
480
+ this.#reportFailure(new reactAdapterError.ReactAdapterError(
481
+ "REACT_CALLBACK_FAILED",
482
+ "Adapter scope microtask scheduler failed.",
483
+ {
484
+ cause,
485
+ details: { field: "scope.scheduleMicrotask", phase: "lifecycle" },
486
+ },
487
+ ));
488
+ callback();
489
+ }
490
+ }
491
+
492
+ /** Reporter failure nikdy neovlivní scope lifecycle. */
493
+ #reportFailure(error: reactAdapterError.ReactAdapterError): void {
494
+ try {
495
+ this.#reportLifecycleFailure?.(error);
496
+ } catch {
497
+ // Diagnostic seam nemá lifecycle autoritu.
498
+ }
499
+ }
500
+ }
@@ -0,0 +1,59 @@
1
+ /** Callable loader zachycený z platného structural managed-lazy descriptoru. */
2
+ export type CapturedReactLazyLoader = (input: unknown) => unknown;
3
+
4
+ /** Shallow klasifikace opaque React contribution implementation hodnoty. */
5
+ export type ReactImplementationClassification =
6
+ | { readonly kind: "eager" }
7
+ | { readonly kind: "managedLazy"; readonly load: CapturedReactLazyLoader }
8
+ | { readonly kind: "invalid" };
9
+
10
+ /** Lifecycle checkpoint mezi jednotlivými user-observable kroky klasifikace. */
11
+ export type ReactImplementationClassificationCheckpoint = () => void;
12
+
13
+ /** Sdílený immutable eager výsledek bez per-call mutable identity. */
14
+ const eagerClassification: ReactImplementationClassification = Object.freeze({ kind: "eager" });
15
+
16
+ /** Sdílený immutable invalid výsledek bez raw hodnoty. */
17
+ const invalidClassification: ReactImplementationClassification = Object.freeze({ kind: "invalid" });
18
+
19
+ /**
20
+ * Provede jedinou normativní shallow klasifikaci React implementation hodnoty.
21
+ *
22
+ * Funkce záměrně nezachytává accessor chyby. Volající hranice rozhoduje, zda je
23
+ * přeloží do Core validator failure nebo pozdější React render chyby.
24
+ */
25
+ export function classifyReactContributionImplementation(
26
+ value: unknown,
27
+ checkpoint: ReactImplementationClassificationCheckpoint = skipReactImplementationClassificationCheckpoint,
28
+ ): ReactImplementationClassification {
29
+ checkpoint();
30
+ const eligible = typeof value === "function"
31
+ || (typeof value === "object" && value !== null && !Array.isArray(value));
32
+ checkpoint();
33
+ if (!eligible) {
34
+ return invalidClassification;
35
+ }
36
+
37
+ const target = value as object;
38
+ const kind = Reflect.get(target, "kind", target);
39
+ checkpoint();
40
+ if (kind !== "contrib-kit-react-lazy") {
41
+ return eagerClassification;
42
+ }
43
+
44
+ const load = Reflect.get(target, "load", target);
45
+ checkpoint();
46
+ if (typeof load !== "function") {
47
+ return invalidClassification;
48
+ }
49
+
50
+ return Object.freeze({
51
+ kind: "managedLazy",
52
+ load: load as CapturedReactLazyLoader,
53
+ });
54
+ }
55
+
56
+ /** Výchozí checkpoint pro klasifikace bez consumer lifecycle autority. */
57
+ function skipReactImplementationClassificationCheckpoint(): void {
58
+ // Core activation validator žádný adapter state nepublikuje.
59
+ }