@2112-lab/central-plant 0.2.10 → 0.3.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.
@@ -1,4 +1,4 @@
1
- import { inherits as _inherits, createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, objectSpread2 as _objectSpread2, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, toConsumableArray as _toConsumableArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, slicedToArray as _slicedToArray, typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { inherits as _inherits, createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, objectSpread2 as _objectSpread2, slicedToArray as _slicedToArray, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, toConsumableArray as _toConsumableArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import * as THREE from 'three';
3
3
  import { Pathfinder } from '@2112-lab/pathfinder';
4
4
  import { BaseDisposable } from '../../core/baseDisposable.js';
@@ -517,6 +517,103 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
517
517
  return this.pathDataStore.get(pathId);
518
518
  }
519
519
 
520
+ /**
521
+ * Propagate flowAttributes from the original connection list to any gateway-split
522
+ * rendered sub-paths in pathDataStore, then apply all flow visualizations.
523
+ * Called after every pathfinding execution (initial load and transform updates).
524
+ *
525
+ * @param {Array} connections - Original connections array (may include flowAttributes)
526
+ * @param {object} pathfindingResult - Result returned by _executePathfinding
527
+ * @private
528
+ */
529
+ }, {
530
+ key: "_propagateFlowAttributesAndApplyVisualizations",
531
+ value: function _propagateFlowAttributesAndApplyVisualizations(connections, pathfindingResult) {
532
+ var _this5 = this,
533
+ _this$sceneViewer;
534
+ if (!Array.isArray(connections) || !pathfindingResult) return;
535
+
536
+ // Pass 1: use the explicit gateway connection mappings to build a precise
537
+ // original-pathId → Set<renderedPathId> map.
538
+ var originalToSubPaths = new Map();
539
+ if (pathfindingResult.gateways) {
540
+ pathfindingResult.gateways.forEach(function (gateway) {
541
+ var _ref = gateway.connections || {},
542
+ removed = _ref.removed,
543
+ added = _ref.added;
544
+ if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
545
+ removed.forEach(function (removedConn) {
546
+ var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
547
+ if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
548
+ added.forEach(function (addedConn) {
549
+ originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
550
+ });
551
+ });
552
+ });
553
+ }
554
+ connections.forEach(function (conn) {
555
+ if (!conn.flowAttributes) return;
556
+ var origId = "".concat(conn.from, "-->").concat(conn.to);
557
+ var subPathIds = new Set(originalToSubPaths.get(origId) || []);
558
+ subPathIds.add(origId);
559
+ subPathIds.forEach(function (subPathId) {
560
+ var pd = _this5.pathDataStore.get(subPathId);
561
+ if (pd && Object.keys(pd.flowAttributes).length === 0) {
562
+ Object.entries(conn.flowAttributes).forEach(function (_ref2) {
563
+ var _ref3 = _slicedToArray(_ref2, 2),
564
+ key = _ref3[0],
565
+ value = _ref3[1];
566
+ return pd.setFlowAttribute(key, value);
567
+ });
568
+ }
569
+ });
570
+ });
571
+
572
+ // Pass 2: endpoint fallback for Gateway→Gateway intermediate segments and
573
+ // for paths whose connections were restructured by manualizeSegment/manualizeGateway.
574
+ // After manualization, currentSceneData.connections no longer contains the original
575
+ // A→B entry with flowAttributes (it's been split into new sub-connections), so we
576
+ // seed the endpoint maps from both the connections array AND from existing pathDataStore
577
+ // entries that already carry flowAttributes — those persist across re-executions.
578
+ var fromEndpointAttrs = new Map();
579
+ var toEndpointAttrs = new Map();
580
+
581
+ // Seed from persisted pathDataStore entries first (covers post-manualization re-runs)
582
+ this.pathDataStore.forEach(function (pd, pathId) {
583
+ if (Object.keys(pd.flowAttributes).length === 0) return;
584
+ var sepIdx = pathId.indexOf('-->');
585
+ if (sepIdx === -1) return;
586
+ var from = pathId.slice(0, sepIdx);
587
+ var to = pathId.slice(sepIdx + 3);
588
+ if (!fromEndpointAttrs.has(from)) fromEndpointAttrs.set(from, pd.flowAttributes);
589
+ if (!toEndpointAttrs.has(to)) toEndpointAttrs.set(to, pd.flowAttributes);
590
+ });
591
+
592
+ // Also seed from connections array (covers initial load before pathDataStore has any attrs)
593
+ connections.forEach(function (conn) {
594
+ if (!conn.flowAttributes) return;
595
+ if (!fromEndpointAttrs.has(conn.from)) fromEndpointAttrs.set(conn.from, conn.flowAttributes);
596
+ if (!toEndpointAttrs.has(conn.to)) toEndpointAttrs.set(conn.to, conn.flowAttributes);
597
+ });
598
+ this.pathDataStore.forEach(function (pd, pathId) {
599
+ if (Object.keys(pd.flowAttributes).length > 0) return;
600
+ var sepIdx = pathId.indexOf('-->');
601
+ if (sepIdx === -1) return;
602
+ var from = pathId.slice(0, sepIdx);
603
+ var to = pathId.slice(sepIdx + 3);
604
+ var attrs = fromEndpointAttrs.get(from) || toEndpointAttrs.get(to);
605
+ if (attrs) Object.entries(attrs).forEach(function (_ref4) {
606
+ var _ref5 = _slicedToArray(_ref4, 2),
607
+ key = _ref5[0],
608
+ value = _ref5[1];
609
+ return pd.setFlowAttribute(key, value);
610
+ });
611
+ });
612
+
613
+ // Apply visualizations
614
+ (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.pathFlowManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.applyAllVisualizations();
615
+ }
616
+
520
617
  /**
521
618
  * Initialize pathfinder and create paths
522
619
  */
@@ -524,9 +621,8 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
524
621
  key: "initializePathfinder",
525
622
  value: (function () {
526
623
  var _initializePathfinder = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(data, crosscubeTextureSet) {
527
- var _this5 = this,
528
- _this$sceneViewer;
529
- var pathfindingResult, originalToSubPaths, fromEndpointAttrs, flowMgr;
624
+ var _this6 = this;
625
+ var pathfindingResult;
530
626
  return _regenerator().w(function (_context2) {
531
627
  while (1) switch (_context2.n) {
532
628
  case 0:
@@ -539,11 +635,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
539
635
  data.connections.forEach(function (conn) {
540
636
  if (conn.flowAttributes && _typeof(conn.flowAttributes) === 'object') {
541
637
  var pathId = "".concat(conn.from, "-->").concat(conn.to);
542
- var pd = _this5._getOrCreatePathData(pathId, conn.from, conn.to);
543
- Object.entries(conn.flowAttributes).forEach(function (_ref) {
544
- var _ref2 = _slicedToArray(_ref, 2),
545
- key = _ref2[0],
546
- value = _ref2[1];
638
+ var pd = _this6._getOrCreatePathData(pathId, conn.from, conn.to);
639
+ Object.entries(conn.flowAttributes).forEach(function (_ref6) {
640
+ var _ref7 = _slicedToArray(_ref6, 2),
641
+ key = _ref7[0],
642
+ value = _ref7[1];
547
643
  pd.setFlowAttribute(key, value);
548
644
  });
549
645
  console.log("\uD83C\uDF0A Loaded flowAttributes for path \"".concat(pathId, "\":"), conn.flowAttributes);
@@ -559,82 +655,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
559
655
  });
560
656
  case 1:
561
657
  pathfindingResult = _context2.v;
562
- // ── Propagate flowAttributes to gateway-split rendered paths ──────────
563
- // The pathfinder may split a connection A→B through gateway waypoints,
564
- // producing sub-paths like A→G and G→B with different pathIds.
565
- // We need to copy the original connection's flowAttributes onto every
566
- // rendered sub-path entry in pathDataStore so the visualisation can
567
- // find them by their rendered pathId.
568
- if (Array.isArray(data.connections) && pathfindingResult) {
569
- // Pass 1: use the explicit gateway connection mappings to get a precise
570
- // original→sub-path map.
571
- originalToSubPaths = new Map(); // origPathId → Set<renderedPathId>
572
- if (pathfindingResult.gateways) {
573
- pathfindingResult.gateways.forEach(function (gateway) {
574
- var _ref3 = gateway.connections || {},
575
- removed = _ref3.removed,
576
- added = _ref3.added;
577
- if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
578
- removed.forEach(function (removedConn) {
579
- var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
580
- if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
581
- added.forEach(function (addedConn) {
582
- originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
583
- });
584
- });
585
- });
586
- }
587
- data.connections.forEach(function (conn) {
588
- if (!conn.flowAttributes) return;
589
- var origId = "".concat(conn.from, "-->").concat(conn.to);
590
- var subPathIds = new Set(originalToSubPaths.get(origId) || []);
591
- subPathIds.add(origId); // include the direct path if it wasn't rewired
592
-
593
- subPathIds.forEach(function (subPathId) {
594
- var pd = _this5.pathDataStore.get(subPathId);
595
- if (pd && Object.keys(pd.flowAttributes).length === 0) {
596
- Object.entries(conn.flowAttributes).forEach(function (_ref4) {
597
- var _ref5 = _slicedToArray(_ref4, 2),
598
- key = _ref5[0],
599
- value = _ref5[1];
600
- pd.setFlowAttribute(key, value);
601
- });
602
- console.log("\uD83C\uDF0A Propagated flowAttributes to sub-path \"".concat(subPathId, "\" from \"").concat(origId, "\""));
603
- }
604
- });
605
- });
606
-
607
- // Pass 2: endpoint fallback for any rendered path still missing attributes
608
- // (covers Gateway→Gateway intermediate segments not captured by gateway.connections.added)
609
- fromEndpointAttrs = new Map(); // connectorId → flowAttributes
610
- data.connections.forEach(function (conn) {
611
- if (conn.flowAttributes && !fromEndpointAttrs.has(conn.from)) {
612
- fromEndpointAttrs.set(conn.from, conn.flowAttributes);
613
- }
614
- });
615
- this.pathDataStore.forEach(function (pd, pathId) {
616
- if (Object.keys(pd.flowAttributes).length > 0) return;
617
- var sepIdx = pathId.indexOf('-->');
618
- if (sepIdx === -1) return;
619
- var from = pathId.slice(0, sepIdx);
620
- var attrs = fromEndpointAttrs.get(from);
621
- if (attrs) {
622
- Object.entries(attrs).forEach(function (_ref6) {
623
- var _ref7 = _slicedToArray(_ref6, 2),
624
- key = _ref7[0],
625
- value = _ref7[1];
626
- return pd.setFlowAttribute(key, value);
627
- });
628
- console.log("\uD83C\uDF0A Endpoint-matched flowAttributes for path \"".concat(pathId, "\""));
629
- }
630
- });
631
- }
632
-
633
- // ── Apply flow visualizations now that paths are rendered ──────────────
634
- flowMgr = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.pathFlowManager;
635
- if (flowMgr) {
636
- flowMgr.applyAllVisualizations();
637
- }
658
+ this._propagateFlowAttributesAndApplyVisualizations(data.connections, pathfindingResult);
638
659
 
639
660
  // Update connections with rewired connections
640
661
  if (pathfindingResult.rewiredConnections) {
@@ -760,6 +781,9 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
760
781
  });
761
782
  case 2:
762
783
  result = _context3.v;
784
+ // Re-apply flow attribute colors (new materials are created on each execution)
785
+ this._propagateFlowAttributesAndApplyVisualizations(currentSceneData.connections, result);
786
+
763
787
  // Cache fingerprint + result for next comparison
764
788
  this._lastPathfindingFingerprint = fingerprint;
765
789
  this._lastPathfindingResult = result;
@@ -1747,7 +1747,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1747
1747
  if (typeof window !== 'undefined') {
1748
1748
  isDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
1749
1749
  }
1750
- if (isDev && segment.material) {
1750
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true' && segment.material) {
1751
1751
  segment.material.color.setHex(0x0000ff); // Blue
1752
1752
  console.log('🎨 Set manual segment material color to blue (dev mode)');
1753
1753
  }
@@ -1778,7 +1778,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1778
1778
  console.log('🔌 Created connectors:', connectors);
1779
1779
 
1780
1780
  // In dev mode, enlarge connectors by 1.5x and turn them red
1781
- if (isDev) {
1781
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true') {
1782
1782
  connectors.forEach(function (connector) {
1783
1783
  if (connector) {
1784
1784
  connector.scale.set(1.25, 1.25, 1.25);
package/dist/index.d.ts CHANGED
@@ -184,3 +184,122 @@ export * as Numerics from './data/numerics.js';
184
184
  // Analysis utilities
185
185
  export * as Analysis from './analysis/analysis.js';
186
186
  export * as Testing from './analysis/testing.js';
187
+
188
+ // ─── Cache management ─────────────────────────────────────────────────────────
189
+
190
+ export interface CacheExpiryConfig {
191
+ MODELS: number
192
+ TEXTURES: number
193
+ JSON: number
194
+ COMPONENT_DICTIONARY: number
195
+ SCENE_DATA: number
196
+ THUMBNAILS: number
197
+ SKYBOXES: number
198
+ USER_CONTENT: number
199
+ TEMPORARY: number
200
+ DEFAULT: number
201
+ }
202
+
203
+ export declare const CACHE_EXPIRY: CacheExpiryConfig
204
+ export declare const CACHE_NAME_PREFIX: string
205
+ export declare const GLOBAL_CACHE_NAME: string
206
+
207
+ export interface CacheStatsItem {
208
+ url: string
209
+ sourceKey?: string
210
+ s3Key?: string
211
+ size: number
212
+ sizeMB: string
213
+ type: string
214
+ cachedTime: number
215
+ age: number
216
+ isLocal?: boolean
217
+ }
218
+
219
+ export interface CacheStatsResult {
220
+ count: number
221
+ totalSize: number
222
+ totalSizeMB: string
223
+ items: CacheStatsItem[]
224
+ }
225
+
226
+ export interface CacheGlobalStats {
227
+ hits: number
228
+ misses: number
229
+ errors: number
230
+ totalBytesServed: number
231
+ totalBytesCached: number
232
+ startTime: number
233
+ hitRate: string
234
+ totalMBServed: string
235
+ totalMBCached: string
236
+ uptimeMinutes: string
237
+ }
238
+
239
+ export declare class CacheManager {
240
+ stats: { hits: number; misses: number; errors: number; totalBytesServed: number; totalBytesCached: number; startTime: number }
241
+ configure(options: { getUser?: () => Promise<any>; onError?: (error: Error) => void }): void
242
+ getExpiryForPath(path: string, assetType?: string | null): number
243
+ resetIdentity(): void
244
+ getCacheName(): Promise<string>
245
+ execute(options: { cacheKey: string; sourceKey?: string; expiryMs: number; fetcher: () => Promise<any>; processor: (response: any) => Promise<any>; metadata?: Record<string, string>; logType?: string }): Promise<any>
246
+ getGlobalStats(): CacheGlobalStats
247
+ resetStats(): void
248
+ clearCache(specificKey?: string | null, clearAllUsers?: boolean): Promise<boolean>
249
+ cleanExpired(): Promise<number>
250
+ cleanInvalid(): Promise<number>
251
+ has(cacheKey: string, expiryMs?: number | null): Promise<boolean>
252
+ get(cacheKey: string, expiryMs?: number | null, processor?: (response: Response) => Promise<any>): Promise<any>
253
+ delete(cacheKey: string): Promise<boolean>
254
+ deleteCache(cacheName: string): Promise<boolean>
255
+ getDetailedStats(allUsers?: boolean): Promise<CacheStatsResult | { caches: any[]; totalCaches: number; grandTotalSizeMB: string }>
256
+ }
257
+
258
+ export declare const cacheManager: CacheManager
259
+
260
+ export declare function resetCacheIdentity(): void
261
+ export declare function getGlobalCacheStats(): CacheGlobalStats
262
+ export declare function resetGlobalCacheStats(): void
263
+ export declare function getCurrentCacheName(): Promise<string>
264
+ export declare function cleanExpiredCache(): Promise<number>
265
+ export declare function cleanInvalidCacheEntries(): Promise<number>
266
+ export declare function getCacheStats(allUsers?: boolean): Promise<CacheStatsResult>
267
+ export declare function getUserOnlyCacheStats(allUsers?: boolean): Promise<CacheStatsResult>
268
+ export declare function getGlobalOnlyCacheStats(): Promise<CacheStatsResult>
269
+ export declare function clearS3Cache(specificKey?: string | null, clearAllUsers?: boolean): Promise<boolean>
270
+ export declare function getAllCacheKeys(): Promise<Set<string>>
271
+ export declare function switchCachePartition(isAuthenticated: boolean): Promise<{ oldCacheName: string; newCacheName: string; deletedPartition: string | null; deleted: boolean } | { error: string }>
272
+
273
+ export declare function getCachedS3Object(s3Key: string, storageOptions?: Record<string, any>, expiryMs?: number | null): Promise<Blob>
274
+ export declare function getCachedS3ObjectURL(s3Key: string, storageOptions?: Record<string, any>, expiryMs?: number | null): Promise<string>
275
+ export declare function preloadS3Objects(s3Keys: string[], storageOptions?: Record<string, any>): Promise<{ success: number; failed: number; errors: Array<{ key: string; error: string }> }>
276
+ export declare function getCachedS3Json(s3Key: string, storageOptions?: Record<string, any>, expiryMs?: number | null): Promise<any>
277
+ export declare function getCachedLocalJson(localPath: string, expiryMs?: number | null): Promise<any>
278
+ export declare function getCachedLocalFile(url: string, expiryMs?: number | null): Promise<Blob>
279
+ export declare function getCachedLocalFileURL(url: string, expiryMs?: number | null): Promise<string>
280
+ export declare function preloadLocalFiles(urls: string[]): Promise<{ success: number; failed: number; errors: Array<{ url: string; error: string }> }>
281
+
282
+ export declare function cacheJsonData(key: string, data: any, expiryMs?: number): Promise<boolean>
283
+ export declare function getCachedJsonData(key: string, expiryMs?: number): Promise<any>
284
+ export declare function removeCachedJsonData(key: string): Promise<boolean>
285
+
286
+ export declare function getThumbnailKey(asset: { thumbnailS3Path?: string; s3Path?: string; uuid?: string; id?: string }): string | null
287
+ export declare function isThumbnailCached(asset: { isS3Component?: boolean; source?: string; scope?: string; thumbnailS3Path?: string; s3Path?: string; uuid?: string; id?: string }): Promise<boolean>
288
+ export declare function isCached(s3Key: string, expiryMs?: number | null): Promise<boolean>
289
+ export declare function getCacheExpiryForPath(path: string, assetType?: string | null): number
290
+ export declare function formatCacheExpiry(ms: number): string
291
+
292
+ export declare class S3MetadataCacheService {
293
+ getAll(): Promise<any[]>
294
+ getMetadata(): Promise<{ version: number; components: any[]; timestamp: number }>
295
+ addComponent(component: { id?: string; uuid?: string; [key: string]: any }): Promise<boolean>
296
+ removeComponent(identifier: string): Promise<boolean>
297
+ clear(): Promise<boolean>
298
+ hasComponent(identifier: string): Promise<boolean>
299
+ refresh(): Promise<any[]>
300
+ setAll(components: any[]): Promise<boolean>
301
+ }
302
+
303
+ export declare const s3MetadataCache: S3MetadataCacheService
304
+
305
+ export declare function measureS3Transfer(operation: string, asyncFn: () => Promise<any>, fileSize?: number | null): Promise<any>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.2.10",
3
+ "version": "0.3.0",
4
4
  "description": "Utility modules for the Central Plant Application",
5
5
  "main": "dist/bundle/index.js",
6
6
  "module": "dist/esm/src/index.js",
@@ -32,6 +32,7 @@
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
34
  "@2112-lab/pathfinder": "^1.0.38",
35
+ "aws-amplify": "^5.3.33",
35
36
  "stats.js": "^0.17.0",
36
37
  "three": "^0.177.0"
37
38
  },