@memberjunction/react-runtime 2.76.0 → 2.78.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 (35) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +10 -1
  6. package/dist/registry/component-registry.d.ts +1 -0
  7. package/dist/registry/component-registry.d.ts.map +1 -1
  8. package/dist/registry/component-registry.js +6 -3
  9. package/dist/runtime/index.d.ts +1 -0
  10. package/dist/runtime/index.d.ts.map +1 -1
  11. package/dist/runtime/index.js +4 -1
  12. package/dist/runtime/react-root-manager.d.ts +26 -0
  13. package/dist/runtime/react-root-manager.d.ts.map +1 -0
  14. package/dist/runtime/react-root-manager.js +122 -0
  15. package/dist/utilities/cache-manager.d.ts +38 -0
  16. package/dist/utilities/cache-manager.d.ts.map +1 -0
  17. package/dist/utilities/cache-manager.js +156 -0
  18. package/dist/utilities/index.d.ts +2 -0
  19. package/dist/utilities/index.d.ts.map +1 -1
  20. package/dist/utilities/index.js +2 -0
  21. package/dist/utilities/library-loader.d.ts.map +1 -1
  22. package/dist/utilities/library-loader.js +25 -8
  23. package/dist/utilities/resource-manager.d.ts +36 -0
  24. package/dist/utilities/resource-manager.d.ts.map +1 -0
  25. package/dist/utilities/resource-manager.js +225 -0
  26. package/package.json +4 -4
  27. package/src/index.ts +18 -0
  28. package/src/registry/component-registry.ts +14 -4
  29. package/src/runtime/index.ts +7 -1
  30. package/src/runtime/react-root-manager.ts +218 -0
  31. package/src/utilities/cache-manager.ts +253 -0
  32. package/src/utilities/index.ts +3 -1
  33. package/src/utilities/library-loader.ts +66 -21
  34. package/src/utilities/resource-manager.ts +371 -0
  35. package/tsconfig.tsbuildinfo +1 -1
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LibraryLoader = void 0;
4
4
  const standard_libraries_1 = require("./standard-libraries");
5
5
  const core_libraries_1 = require("./core-libraries");
6
+ const resource_manager_1 = require("./resource-manager");
7
+ const LIBRARY_LOADER_COMPONENT_ID = 'mj-react-runtime-library-loader-singleton';
6
8
  class LibraryLoader {
7
9
  static async loadAllLibraries(config, additionalLibraries) {
8
10
  if (config) {
@@ -98,13 +100,18 @@ class LibraryLoader {
98
100
  script.src = url;
99
101
  script.async = true;
100
102
  script.crossOrigin = 'anonymous';
101
- script.onload = () => {
103
+ const cleanup = () => {
104
+ script.removeEventListener('load', onLoad);
105
+ script.removeEventListener('error', onError);
106
+ };
107
+ const onLoad = () => {
108
+ cleanup();
102
109
  const global = window[globalName];
103
110
  if (global) {
104
111
  resolve(global);
105
112
  }
106
113
  else {
107
- setTimeout(() => {
114
+ const timeoutId = resource_manager_1.resourceManager.setTimeout(LIBRARY_LOADER_COMPONENT_ID, () => {
108
115
  const delayedGlobal = window[globalName];
109
116
  if (delayedGlobal) {
110
117
  resolve(delayedGlobal);
@@ -112,13 +119,17 @@ class LibraryLoader {
112
119
  else {
113
120
  reject(new Error(`${globalName} not found after script load`));
114
121
  }
115
- }, 100);
122
+ }, 100, { url, globalName });
116
123
  }
117
124
  };
118
- script.onerror = () => {
125
+ const onError = () => {
126
+ cleanup();
119
127
  reject(new Error(`Failed to load script: ${url}`));
120
128
  };
129
+ script.addEventListener('load', onLoad);
130
+ script.addEventListener('error', onError);
121
131
  document.head.appendChild(script);
132
+ resource_manager_1.resourceManager.registerDOMElement(LIBRARY_LOADER_COMPONENT_ID, script);
122
133
  });
123
134
  this.loadedResources.set(url, {
124
135
  element: document.querySelector(`script[src="${url}"]`),
@@ -138,6 +149,7 @@ class LibraryLoader {
138
149
  link.rel = 'stylesheet';
139
150
  link.href = url;
140
151
  document.head.appendChild(link);
152
+ resource_manager_1.resourceManager.registerDOMElement(LIBRARY_LOADER_COMPONENT_ID, link);
141
153
  this.loadedResources.set(url, {
142
154
  element: link,
143
155
  promise: Promise.resolve()
@@ -150,7 +162,7 @@ class LibraryLoader {
150
162
  resolve(global);
151
163
  }
152
164
  else {
153
- setTimeout(() => {
165
+ resource_manager_1.resourceManager.setTimeout(LIBRARY_LOADER_COMPONENT_ID, () => {
154
166
  const delayedGlobal = window[globalName];
155
167
  if (delayedGlobal) {
156
168
  resolve(delayedGlobal);
@@ -158,7 +170,7 @@ class LibraryLoader {
158
170
  else {
159
171
  reject(new Error(`${globalName} not found after script load`));
160
172
  }
161
- }, 100);
173
+ }, 100, { context: 'waitForScriptLoad', globalName });
162
174
  }
163
175
  };
164
176
  if (script.complete || script.readyState === 'complete') {
@@ -166,16 +178,21 @@ class LibraryLoader {
166
178
  return;
167
179
  }
168
180
  const loadHandler = () => {
169
- script.removeEventListener('load', loadHandler);
170
181
  checkGlobal();
171
182
  };
172
- script.addEventListener('load', loadHandler);
183
+ resource_manager_1.resourceManager.addEventListener(LIBRARY_LOADER_COMPONENT_ID, script, 'load', loadHandler, { once: true });
173
184
  }
174
185
  static getLoadedResources() {
175
186
  return this.loadedResources;
176
187
  }
177
188
  static clearCache() {
189
+ this.loadedResources.forEach((resource, url) => {
190
+ if (resource.element && resource.element.parentNode) {
191
+ resource.element.parentNode.removeChild(resource.element);
192
+ }
193
+ });
178
194
  this.loadedResources.clear();
195
+ resource_manager_1.resourceManager.cleanupComponent(LIBRARY_LOADER_COMPONENT_ID);
179
196
  }
180
197
  }
181
198
  exports.LibraryLoader = LibraryLoader;
@@ -0,0 +1,36 @@
1
+ /// <reference types="node" />
2
+ export type TimerId = number | NodeJS.Timeout;
3
+ export interface ManagedResource {
4
+ type: 'timer' | 'interval' | 'animationFrame' | 'eventListener' | 'domElement' | 'observable' | 'reactRoot';
5
+ id: string | TimerId;
6
+ cleanup: () => void;
7
+ metadata?: Record<string, any>;
8
+ }
9
+ export declare class ResourceManager {
10
+ private resources;
11
+ private globalResources;
12
+ private cleanupCallbacks;
13
+ setTimeout(componentId: string, callback: () => void, delay: number, metadata?: Record<string, any>): number;
14
+ setInterval(componentId: string, callback: () => void, delay: number, metadata?: Record<string, any>): number;
15
+ requestAnimationFrame(componentId: string, callback: FrameRequestCallback, metadata?: Record<string, any>): TimerId;
16
+ clearTimeout(componentId: string, id: number): void;
17
+ clearInterval(componentId: string, id: number): void;
18
+ cancelAnimationFrame(componentId: string, id: TimerId): void;
19
+ addEventListener(componentId: string, target: EventTarget, type: string, listener: EventListener, options?: AddEventListenerOptions): void;
20
+ registerDOMElement(componentId: string, element: any, cleanup?: () => void): void;
21
+ registerReactRoot(componentId: string, root: any, unmountFn: () => void): void;
22
+ registerCleanup(componentId: string, cleanup: () => void): void;
23
+ registerGlobalResource(resource: ManagedResource): void;
24
+ private addResource;
25
+ private removeResource;
26
+ cleanupComponent(componentId: string): void;
27
+ cleanupGlobal(): void;
28
+ cleanupAll(): void;
29
+ getStats(): {
30
+ componentCount: number;
31
+ resourceCounts: Record<string, number>;
32
+ globalResourceCount: number;
33
+ };
34
+ }
35
+ export declare const resourceManager: ResourceManager;
36
+ //# sourceMappingURL=resource-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-manager.d.ts","sourceRoot":"","sources":["../../src/utilities/resource-manager.ts"],"names":[],"mappings":";AAOA,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,gBAAgB,GAAG,eAAe,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,CAAC;IAC5G,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAiDD,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAA2C;IAC5D,OAAO,CAAC,eAAe,CAA8B;IACrD,OAAO,CAAC,gBAAgB,CAAqC;IAK7D,UAAU,CACR,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,IAAI,EACpB,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,MAAM;IAmBT,WAAW,CACT,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,IAAI,EACpB,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,MAAM;IAgBT,qBAAqB,CACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,oBAAoB,EAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,OAAO;IAwBV,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAQnD,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAQpD,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI;IAa5D,gBAAgB,CACd,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,EACvB,OAAO,CAAC,EAAE,uBAAuB,GAChC,IAAI;IAsBP,kBAAkB,CAChB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,GAAG,EACZ,OAAO,CAAC,EAAE,MAAM,IAAI,GACnB,IAAI;IAuBP,iBAAiB,CACf,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,GAAG,EACT,SAAS,EAAE,MAAM,IAAI,GACpB,IAAI;IAYP,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAU/D,sBAAsB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAOvD,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,cAAc;IAmBtB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IA+B3C,aAAa,IAAI,IAAI;IAcrB,UAAU,IAAI,IAAI;IAalB,QAAQ,IAAI;QACV,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACvC,mBAAmB,EAAE,MAAM,CAAC;KAC7B;CAeF;AAGD,eAAO,MAAM,eAAe,iBAAwB,CAAC"}
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resourceManager = exports.ResourceManager = void 0;
4
+ const getTimerFunctions = () => {
5
+ if (typeof window !== 'undefined' && window.setTimeout) {
6
+ return {
7
+ setTimeout: window.setTimeout.bind(window),
8
+ clearTimeout: window.clearTimeout.bind(window),
9
+ setInterval: window.setInterval.bind(window),
10
+ clearInterval: window.clearInterval.bind(window),
11
+ requestAnimationFrame: window.requestAnimationFrame?.bind(window),
12
+ cancelAnimationFrame: window.cancelAnimationFrame?.bind(window)
13
+ };
14
+ }
15
+ else if (typeof global !== 'undefined' && global.setTimeout) {
16
+ return {
17
+ setTimeout: global.setTimeout,
18
+ clearTimeout: global.clearTimeout,
19
+ setInterval: global.setInterval,
20
+ clearInterval: global.clearInterval,
21
+ requestAnimationFrame: undefined,
22
+ cancelAnimationFrame: undefined
23
+ };
24
+ }
25
+ else {
26
+ const noop = () => { };
27
+ const noopWithReturn = () => 0;
28
+ return {
29
+ setTimeout: noopWithReturn,
30
+ clearTimeout: noop,
31
+ setInterval: noopWithReturn,
32
+ clearInterval: noop,
33
+ requestAnimationFrame: undefined,
34
+ cancelAnimationFrame: undefined
35
+ };
36
+ }
37
+ };
38
+ const timers = getTimerFunctions();
39
+ class ResourceManager {
40
+ constructor() {
41
+ this.resources = new Map();
42
+ this.globalResources = new Set();
43
+ this.cleanupCallbacks = new Map();
44
+ }
45
+ setTimeout(componentId, callback, delay, metadata) {
46
+ const id = timers.setTimeout(() => {
47
+ this.removeResource(componentId, 'timer', id);
48
+ callback();
49
+ }, delay);
50
+ this.addResource(componentId, {
51
+ type: 'timer',
52
+ id,
53
+ cleanup: () => timers.clearTimeout(id),
54
+ metadata
55
+ });
56
+ return id;
57
+ }
58
+ setInterval(componentId, callback, delay, metadata) {
59
+ const id = timers.setInterval(callback, delay);
60
+ this.addResource(componentId, {
61
+ type: 'interval',
62
+ id,
63
+ cleanup: () => timers.clearInterval(id),
64
+ metadata
65
+ });
66
+ return id;
67
+ }
68
+ requestAnimationFrame(componentId, callback, metadata) {
69
+ if (!timers.requestAnimationFrame) {
70
+ return this.setTimeout(componentId, () => callback(Date.now()), 16, metadata);
71
+ }
72
+ const id = timers.requestAnimationFrame((time) => {
73
+ this.removeResource(componentId, 'animationFrame', id);
74
+ callback(time);
75
+ });
76
+ this.addResource(componentId, {
77
+ type: 'animationFrame',
78
+ id,
79
+ cleanup: () => timers.cancelAnimationFrame?.(id),
80
+ metadata
81
+ });
82
+ return id;
83
+ }
84
+ clearTimeout(componentId, id) {
85
+ timers.clearTimeout(id);
86
+ this.removeResource(componentId, 'timer', id);
87
+ }
88
+ clearInterval(componentId, id) {
89
+ timers.clearInterval(id);
90
+ this.removeResource(componentId, 'interval', id);
91
+ }
92
+ cancelAnimationFrame(componentId, id) {
93
+ if (timers.cancelAnimationFrame) {
94
+ timers.cancelAnimationFrame(id);
95
+ }
96
+ else {
97
+ timers.clearTimeout(id);
98
+ }
99
+ this.removeResource(componentId, 'animationFrame', id);
100
+ }
101
+ addEventListener(componentId, target, type, listener, options) {
102
+ if (target && typeof target.addEventListener === 'function') {
103
+ target.addEventListener(type, listener, options);
104
+ const resourceId = `${type}-${Date.now()}-${Math.random()}`;
105
+ this.addResource(componentId, {
106
+ type: 'eventListener',
107
+ id: resourceId,
108
+ cleanup: () => {
109
+ if (target && typeof target.removeEventListener === 'function') {
110
+ target.removeEventListener(type, listener, options);
111
+ }
112
+ },
113
+ metadata: { target, type, options }
114
+ });
115
+ }
116
+ }
117
+ registerDOMElement(componentId, element, cleanup) {
118
+ if (typeof document !== 'undefined' && element && element.parentNode) {
119
+ const resourceId = `dom-${Date.now()}-${Math.random()}`;
120
+ this.addResource(componentId, {
121
+ type: 'domElement',
122
+ id: resourceId,
123
+ cleanup: () => {
124
+ if (cleanup) {
125
+ cleanup();
126
+ }
127
+ if (element && element.parentNode && typeof element.parentNode.removeChild === 'function') {
128
+ element.parentNode.removeChild(element);
129
+ }
130
+ },
131
+ metadata: { element }
132
+ });
133
+ }
134
+ }
135
+ registerReactRoot(componentId, root, unmountFn) {
136
+ this.addResource(componentId, {
137
+ type: 'reactRoot',
138
+ id: `react-root-${componentId}`,
139
+ cleanup: unmountFn,
140
+ metadata: { root }
141
+ });
142
+ }
143
+ registerCleanup(componentId, cleanup) {
144
+ if (!this.cleanupCallbacks.has(componentId)) {
145
+ this.cleanupCallbacks.set(componentId, []);
146
+ }
147
+ this.cleanupCallbacks.get(componentId).push(cleanup);
148
+ }
149
+ registerGlobalResource(resource) {
150
+ this.globalResources.add(resource);
151
+ }
152
+ addResource(componentId, resource) {
153
+ if (!this.resources.has(componentId)) {
154
+ this.resources.set(componentId, new Set());
155
+ }
156
+ this.resources.get(componentId).add(resource);
157
+ }
158
+ removeResource(componentId, type, id) {
159
+ const componentResources = this.resources.get(componentId);
160
+ if (componentResources) {
161
+ const toRemove = Array.from(componentResources).find(r => r.type === type && r.id === id);
162
+ if (toRemove) {
163
+ componentResources.delete(toRemove);
164
+ }
165
+ }
166
+ }
167
+ cleanupComponent(componentId) {
168
+ const componentResources = this.resources.get(componentId);
169
+ if (componentResources) {
170
+ componentResources.forEach(resource => {
171
+ try {
172
+ resource.cleanup();
173
+ }
174
+ catch (error) {
175
+ console.error(`Error cleaning up ${resource.type} resource:`, error);
176
+ }
177
+ });
178
+ this.resources.delete(componentId);
179
+ }
180
+ const callbacks = this.cleanupCallbacks.get(componentId);
181
+ if (callbacks) {
182
+ callbacks.forEach(callback => {
183
+ try {
184
+ callback();
185
+ }
186
+ catch (error) {
187
+ console.error('Error executing cleanup callback:', error);
188
+ }
189
+ });
190
+ this.cleanupCallbacks.delete(componentId);
191
+ }
192
+ }
193
+ cleanupGlobal() {
194
+ this.globalResources.forEach(resource => {
195
+ try {
196
+ resource.cleanup();
197
+ }
198
+ catch (error) {
199
+ console.error(`Error cleaning up global ${resource.type} resource:`, error);
200
+ }
201
+ });
202
+ this.globalResources.clear();
203
+ }
204
+ cleanupAll() {
205
+ for (const componentId of this.resources.keys()) {
206
+ this.cleanupComponent(componentId);
207
+ }
208
+ this.cleanupGlobal();
209
+ }
210
+ getStats() {
211
+ const resourceCounts = {};
212
+ for (const resources of this.resources.values()) {
213
+ resources.forEach(resource => {
214
+ resourceCounts[resource.type] = (resourceCounts[resource.type] || 0) + 1;
215
+ });
216
+ }
217
+ return {
218
+ componentCount: this.resources.size,
219
+ resourceCounts,
220
+ globalResourceCount: this.globalResources.size
221
+ };
222
+ }
223
+ }
224
+ exports.ResourceManager = ResourceManager;
225
+ exports.resourceManager = new ResourceManager();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/react-runtime",
3
- "version": "2.76.0",
3
+ "version": "2.78.0",
4
4
  "description": "Platform-agnostic React component runtime for MemberJunction. Provides core compilation, registry, and execution capabilities for React components in any JavaScript environment.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,9 +25,9 @@
25
25
  },
26
26
  "homepage": "https://github.com/MemberJunction/MJ#readme",
27
27
  "dependencies": {
28
- "@memberjunction/core": "2.76.0",
29
- "@memberjunction/global": "2.76.0",
30
- "@memberjunction/interactive-component-types": "2.76.0",
28
+ "@memberjunction/core": "2.78.0",
29
+ "@memberjunction/global": "2.78.0",
30
+ "@memberjunction/interactive-component-types": "2.78.0",
31
31
  "@babel/standalone": "^7.23.5",
32
32
  "rxjs": "^7.8.1"
33
33
  },
package/src/index.ts CHANGED
@@ -74,6 +74,12 @@ export {
74
74
  HierarchyRegistrationOptions
75
75
  } from './runtime';
76
76
 
77
+ export {
78
+ ReactRootManager,
79
+ reactRootManager,
80
+ ManagedReactRoot
81
+ } from './runtime';
82
+
77
83
  // Export utilities
78
84
  export {
79
85
  RuntimeUtilities,
@@ -102,6 +108,18 @@ export {
102
108
  FailedComponentInfo
103
109
  } from './utilities/component-error-analyzer';
104
110
 
111
+ export {
112
+ ResourceManager,
113
+ resourceManager,
114
+ ManagedResource
115
+ } from './utilities/resource-manager';
116
+
117
+ export {
118
+ CacheManager,
119
+ CacheEntry,
120
+ CacheOptions
121
+ } from './utilities/cache-manager';
122
+
105
123
  // Version information
106
124
  export const VERSION = '2.69.1';
107
125
 
@@ -9,6 +9,7 @@ import {
9
9
  ComponentMetadata,
10
10
  RegistryConfig
11
11
  } from '../types';
12
+ import { resourceManager } from '../utilities/resource-manager';
12
13
 
13
14
  /**
14
15
  * Default registry configuration
@@ -28,6 +29,7 @@ export class ComponentRegistry {
28
29
  private registry: Map<string, RegistryEntry>;
29
30
  private config: RegistryConfig;
30
31
  private cleanupTimer?: NodeJS.Timeout | number;
32
+ private registryId: string;
31
33
 
32
34
  /**
33
35
  * Creates a new ComponentRegistry instance
@@ -36,6 +38,7 @@ export class ComponentRegistry {
36
38
  constructor(config?: Partial<RegistryConfig>) {
37
39
  this.config = { ...DEFAULT_REGISTRY_CONFIG, ...config };
38
40
  this.registry = new Map();
41
+ this.registryId = `component-registry-${Date.now()}`;
39
42
 
40
43
  // Start cleanup timer if configured
41
44
  if (this.config.cleanupInterval > 0) {
@@ -297,6 +300,8 @@ export class ComponentRegistry {
297
300
  destroy(): void {
298
301
  this.stopCleanupTimer();
299
302
  this.clear();
303
+ // Clean up any resources associated with this registry
304
+ resourceManager.cleanupComponent(this.registryId);
300
305
  }
301
306
 
302
307
  /**
@@ -362,9 +367,14 @@ export class ComponentRegistry {
362
367
  * Starts the automatic cleanup timer
363
368
  */
364
369
  private startCleanupTimer(): void {
365
- this.cleanupTimer = setInterval(() => {
366
- this.cleanup();
367
- }, this.config.cleanupInterval);
370
+ this.cleanupTimer = resourceManager.setInterval(
371
+ this.registryId,
372
+ () => {
373
+ this.cleanup();
374
+ },
375
+ this.config.cleanupInterval,
376
+ { purpose: 'component-registry-cleanup' }
377
+ );
368
378
  }
369
379
 
370
380
  /**
@@ -372,7 +382,7 @@ export class ComponentRegistry {
372
382
  */
373
383
  private stopCleanupTimer(): void {
374
384
  if (this.cleanupTimer) {
375
- clearInterval(this.cleanupTimer as any);
385
+ resourceManager.clearInterval(this.registryId, this.cleanupTimer as number);
376
386
  this.cleanupTimer = undefined;
377
387
  }
378
388
  }
@@ -42,4 +42,10 @@ export {
42
42
  HierarchyRegistrationResult,
43
43
  ComponentRegistrationError,
44
44
  HierarchyRegistrationOptions
45
- } from './component-hierarchy';
45
+ } from './component-hierarchy';
46
+
47
+ export {
48
+ ReactRootManager,
49
+ reactRootManager,
50
+ ManagedReactRoot
51
+ } from './react-root-manager';