@fnndsc/cumin 3.2.4

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 (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +78 -0
  3. package/dist/activities/chrisActivity.d.ts +19 -0
  4. package/dist/activities/chrisActivity.js +29 -0
  5. package/dist/activities/chrisActivity.js.map +1 -0
  6. package/dist/cache/index.d.ts +9 -0
  7. package/dist/cache/index.js +15 -0
  8. package/dist/cache/index.js.map +1 -0
  9. package/dist/cache/listCache.d.ts +182 -0
  10. package/dist/cache/listCache.js +266 -0
  11. package/dist/cache/listCache.js.map +1 -0
  12. package/dist/cache/procCache.d.ts +150 -0
  13. package/dist/cache/procCache.js +257 -0
  14. package/dist/cache/procCache.js.map +1 -0
  15. package/dist/cli.d.ts +7 -0
  16. package/dist/cli.js +43 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/compute/computeResources.d.ts +65 -0
  19. package/dist/compute/computeResources.js +113 -0
  20. package/dist/compute/computeResources.js.map +1 -0
  21. package/dist/config/config.d.ts +221 -0
  22. package/dist/config/config.js +350 -0
  23. package/dist/config/config.js.map +1 -0
  24. package/dist/connect/chrisConnection.d.ts +121 -0
  25. package/dist/connect/chrisConnection.js +303 -0
  26. package/dist/connect/chrisConnection.js.map +1 -0
  27. package/dist/context/chrisContext.d.ts +110 -0
  28. package/dist/context/chrisContext.js +324 -0
  29. package/dist/context/chrisContext.js.map +1 -0
  30. package/dist/error/errorStack.d.ts +115 -0
  31. package/dist/error/errorStack.js +175 -0
  32. package/dist/error/errorStack.js.map +1 -0
  33. package/dist/feeds/chrisFeed.d.ts +188 -0
  34. package/dist/feeds/chrisFeed.js +432 -0
  35. package/dist/feeds/chrisFeed.js.map +1 -0
  36. package/dist/filebrowser/chrisFileBrowser.d.ts +77 -0
  37. package/dist/filebrowser/chrisFileBrowser.js +134 -0
  38. package/dist/filebrowser/chrisFileBrowser.js.map +1 -0
  39. package/dist/filebrowser/chrisFiles.d.ts +67 -0
  40. package/dist/filebrowser/chrisFiles.js +130 -0
  41. package/dist/filebrowser/chrisFiles.js.map +1 -0
  42. package/dist/filebrowser/chrisPACS.d.ts +43 -0
  43. package/dist/filebrowser/chrisPACS.js +103 -0
  44. package/dist/filebrowser/chrisPACS.js.map +1 -0
  45. package/dist/filebrowser/chrisPipeline.d.ts +47 -0
  46. package/dist/filebrowser/chrisPipeline.js +118 -0
  47. package/dist/filebrowser/chrisPipeline.js.map +1 -0
  48. package/dist/groups/chrisGroups.d.ts +11 -0
  49. package/dist/groups/chrisGroups.js +18 -0
  50. package/dist/groups/chrisGroups.js.map +1 -0
  51. package/dist/index.d.ts +68 -0
  52. package/dist/index.js +86 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/io/browser_io.d.ts +97 -0
  55. package/dist/io/browser_io.js +149 -0
  56. package/dist/io/browser_io.js.map +1 -0
  57. package/dist/io/chrisIO.d.ts +110 -0
  58. package/dist/io/chrisIO.js +415 -0
  59. package/dist/io/chrisIO.js.map +1 -0
  60. package/dist/io/io.d.ts +21 -0
  61. package/dist/io/io.js +6 -0
  62. package/dist/io/io.js.map +1 -0
  63. package/dist/io/node_io.d.ts +30 -0
  64. package/dist/io/node_io.js +188 -0
  65. package/dist/io/node_io.js.map +1 -0
  66. package/dist/jobs/chrisJob.d.ts +43 -0
  67. package/dist/jobs/chrisJob.js +169 -0
  68. package/dist/jobs/chrisJob.js.map +1 -0
  69. package/dist/jobs/index.d.ts +7 -0
  70. package/dist/jobs/index.js +24 -0
  71. package/dist/jobs/index.js.map +1 -0
  72. package/dist/jobs/jobMonitor.d.ts +46 -0
  73. package/dist/jobs/jobMonitor.js +102 -0
  74. package/dist/jobs/jobMonitor.js.map +1 -0
  75. package/dist/pacs/chrisPACS.d.ts +200 -0
  76. package/dist/pacs/chrisPACS.js +562 -0
  77. package/dist/pacs/chrisPACS.js.map +1 -0
  78. package/dist/path/chrisPath.d.ts +78 -0
  79. package/dist/path/chrisPath.js +190 -0
  80. package/dist/path/chrisPath.js.map +1 -0
  81. package/dist/pipelines/chrisPipeline.d.ts +86 -0
  82. package/dist/pipelines/chrisPipeline.js +180 -0
  83. package/dist/pipelines/chrisPipeline.js.map +1 -0
  84. package/dist/pluginmetas/chrisPluginMetas.d.ts +11 -0
  85. package/dist/pluginmetas/chrisPluginMetas.js +18 -0
  86. package/dist/pluginmetas/chrisPluginMetas.js.map +1 -0
  87. package/dist/plugins/chrisPluginMetaPlugins.d.ts +12 -0
  88. package/dist/plugins/chrisPluginMetaPlugins.js +19 -0
  89. package/dist/plugins/chrisPluginMetaPlugins.js.map +1 -0
  90. package/dist/plugins/chrisPlugins.d.ts +127 -0
  91. package/dist/plugins/chrisPlugins.js +528 -0
  92. package/dist/plugins/chrisPlugins.js.map +1 -0
  93. package/dist/resources/chrisEmbeddedResourceGroup.d.ts +73 -0
  94. package/dist/resources/chrisEmbeddedResourceGroup.js +148 -0
  95. package/dist/resources/chrisEmbeddedResourceGroup.js.map +1 -0
  96. package/dist/resources/chrisObjContext.d.ts +16 -0
  97. package/dist/resources/chrisObjContext.js +109 -0
  98. package/dist/resources/chrisObjContext.js.map +1 -0
  99. package/dist/resources/chrisResourceGroup.d.ts +30 -0
  100. package/dist/resources/chrisResourceGroup.js +47 -0
  101. package/dist/resources/chrisResourceGroup.js.map +1 -0
  102. package/dist/resources/chrisResources.d.ts +163 -0
  103. package/dist/resources/chrisResources.js +415 -0
  104. package/dist/resources/chrisResources.js.map +1 -0
  105. package/dist/tags/chrisTags.d.ts +11 -0
  106. package/dist/tags/chrisTags.js +18 -0
  107. package/dist/tags/chrisTags.js.map +1 -0
  108. package/dist/users/chrisUsers.d.ts +34 -0
  109. package/dist/users/chrisUsers.js +57 -0
  110. package/dist/users/chrisUsers.js.map +1 -0
  111. package/dist/utils/keypair.d.ts +77 -0
  112. package/dist/utils/keypair.js +144 -0
  113. package/dist/utils/keypair.js.map +1 -0
  114. package/dist/utils/result.d.ts +77 -0
  115. package/dist/utils/result.js +58 -0
  116. package/dist/utils/result.js.map +1 -0
  117. package/dist/utils/searchable.d.ts +143 -0
  118. package/dist/utils/searchable.js +212 -0
  119. package/dist/utils/searchable.js.map +1 -0
  120. package/dist/workflows/chrisWorkflows.d.ts +11 -0
  121. package/dist/workflows/chrisWorkflows.js +18 -0
  122. package/dist/workflows/chrisWorkflows.js.map +1 -0
  123. package/package.json +55 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 FNNDSC / BCH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ ```
2
+ ____ _
3
+ / ___| _ ___ ____(_)_ __
4
+ | | | | | | '_ \| '_ \| '_ \
5
+ | |__| |_| | | | | | | | | | |
6
+ \____\__,_|_| |_|_| |_|_| |_|
7
+ ```
8
+ **Cumin Underpins Management Infrastructure Needs**
9
+
10
+ `cumin` is the infrastructure and state management layer of the ChRIS interface ecosystem. It is a backend library that handles the "dirty work" of connecting to ChRIS, managing authentication tokens, and persisting user sessions.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @fnndsc/cumin
16
+ ```
17
+
18
+ Requires Node.js ≥ 20.12. Ships with TypeScript type definitions.
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { ChRISConnection, ChrisContext, ChrisIO } from "@fnndsc/cumin";
24
+
25
+ // The context engine remembers the active user, CUBE URL, and working directory
26
+ const context = new ChrisContext();
27
+ await context.init();
28
+ const cubeURL: string | null = await context.ChRISURL_get();
29
+ ```
30
+
31
+ See [Core Features](#core-features) for the full API surface.
32
+
33
+ ## Abstract
34
+
35
+ `cumin` abstracts the ChRIS REST API into a stateful, object-oriented environment. It is responsible for:
36
+ 1. **Connection Management**: Handling authentication, token storage, and client initialization.
37
+ 2. **Context Persistence**: Implementing the "Context" engine that remembers the active User, CUBE URL, and Working Directory.
38
+ 3. **IO & Storage**: Providing an abstraction (`IStorageProvider`) for filesystem access, enabling support for both Node.js (via `fs`) and other environments.
39
+
40
+ ## Role in the Ecosystem
41
+
42
+ In the "Sandwich Model" architecture, `cumin` is the bottom layer (just above the raw API client).
43
+
44
+ - **Consumers**: Primarily [`salsa`](https://github.com/FNNDSC/salsa) (logic) and [`chili`](https://github.com/FNNDSC/chili) (CLI state).
45
+ - **Environment**: Designed for Node.js but architected with interfaces to support browser environments.
46
+
47
+ ## Core Features
48
+
49
+ - **`ChrisContext`**: The state machine for multi-tenant, multi-backend sessions.
50
+ - **`ChRISConnection`**: Wrapper for the low-level API client.
51
+ - **`IStorageProvider`**: Abstraction interface for reading/writing config and data.
52
+ - Includes `readBinary` for binary file uploads.
53
+ - Includes recursive directory traversal helpers.
54
+ - **`ChrisIO`**: High-level IO operations, including recursive directory uploading (`uploadLocalPath`).
55
+ - **`ChRISResource.resources_getAll()`**: Generic pagination handler.
56
+ - **`ListCache`** (`listCache_get()`): Session-scoped directory listing cache for the VFS.
57
+ - **`ProcCache`** (`procCache_get()`): Session-scoped job monitoring cache. Stores all visible plugin instances as a DAG (two flat maps: `instances` keyed by ID, `children`/`feedRoots` for tree traversal). Structure is permanent once built; only non-terminal instance statuses are refreshed on read. Powers the `/proc/feeds/` VFS provider in salsa.
58
+
59
+ ## Developer Setup
60
+
61
+ To build the `cumin` library from source:
62
+
63
+ 1. **Install dependencies:**
64
+ ```bash
65
+ npm install
66
+ ```
67
+
68
+ 2. **Compile:**
69
+ ```bash
70
+ npm run build
71
+ ```
72
+
73
+ ## License
74
+
75
+ MIT — part of the [ChRIS Project](https://chrisproject.org).
76
+
77
+ ---
78
+ _-30-_
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @file ChRIS Activity
3
+ *
4
+ * This module defines the base Activity class for interactions with ChRIS.
5
+ *
6
+ * @module
7
+ */
8
+ import Client from "@fnndsc/chrisapi";
9
+ /**
10
+ * Base class for ChRIS activities.
11
+ */
12
+ export declare class Activity {
13
+ constructor();
14
+ /**
15
+ * Retrieves the ChRIS client instance asynchronously.
16
+ * @returns A Promise resolving to the Client instance or null.
17
+ */
18
+ client_get(): Promise<Client | null>;
19
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * @file ChRIS Activity
4
+ *
5
+ * This module defines the base Activity class for interactions with ChRIS.
6
+ *
7
+ * @module
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.Activity = void 0;
11
+ const chrisConnection_js_1 = require("../connect/chrisConnection.js");
12
+ /**
13
+ * Base class for ChRIS activities.
14
+ */
15
+ class Activity {
16
+ // private _client: Client | null = null; // No longer needed
17
+ constructor() {
18
+ // Client is fetched lazily
19
+ }
20
+ /**
21
+ * Retrieves the ChRIS client instance asynchronously.
22
+ * @returns A Promise resolving to the Client instance or null.
23
+ */
24
+ async client_get() {
25
+ return await chrisConnection_js_1.chrisConnection.client_get();
26
+ }
27
+ }
28
+ exports.Activity = Activity;
29
+ //# sourceMappingURL=chrisActivity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrisActivity.js","sourceRoot":"","sources":["../../src/activities/chrisActivity.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAGH,sEAAgE;AAEhE;;GAEG;AACH,MAAa,QAAQ;IACnB,6DAA6D;IAE7D;QACE,2BAA2B;IAC7B,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,UAAU;QACrB,OAAO,MAAM,oCAAe,CAAC,UAAU,EAAE,CAAC;IAC5C,CAAC;CACF;AAdD,4BAcC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @file Cache module exports.
3
+ *
4
+ * @module
5
+ */
6
+ export { ListCache, listCache_get } from './listCache.js';
7
+ export type { CacheStats, CacheResult, CacheOptions } from './listCache.js';
8
+ export { ProcCache, procCache_get } from './procCache.js';
9
+ export type { ProcInstance, ProcFeed, ProcWarmupProgress } from './procCache.js';
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.procCache_get = exports.ProcCache = exports.listCache_get = exports.ListCache = void 0;
4
+ /**
5
+ * @file Cache module exports.
6
+ *
7
+ * @module
8
+ */
9
+ var listCache_js_1 = require("./listCache.js");
10
+ Object.defineProperty(exports, "ListCache", { enumerable: true, get: function () { return listCache_js_1.ListCache; } });
11
+ Object.defineProperty(exports, "listCache_get", { enumerable: true, get: function () { return listCache_js_1.listCache_get; } });
12
+ var procCache_js_1 = require("./procCache.js");
13
+ Object.defineProperty(exports, "ProcCache", { enumerable: true, get: function () { return procCache_js_1.ProcCache; } });
14
+ Object.defineProperty(exports, "procCache_get", { enumerable: true, get: function () { return procCache_js_1.procCache_get; } });
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACH,+CAA0D;AAAjD,yGAAA,SAAS,OAAA;AAAE,6GAAA,aAAa,OAAA;AAEjC,+CAA0D;AAAjD,yGAAA,SAAS,OAAA;AAAE,6GAAA,aAAa,OAAA"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * @file Enhanced Directory Listing Cache with TTL and dirty tracking.
3
+ *
4
+ * Provides a singleton cache for directory listings to avoid redundant API calls
5
+ * during tab completion and file operations. Features:
6
+ * - TTL-based expiration (different TTLs per path pattern)
7
+ * - Dirty flag tracking (local mutations mark cache as needing refresh)
8
+ * - LRU eviction (bounded memory usage)
9
+ * - Optimistic serving (serve stale cache while refreshing)
10
+ *
11
+ * Generic implementation - stores any data type keyed by path.
12
+ *
13
+ * @module
14
+ */
15
+ /**
16
+ * Result returned by cache_get with freshness information.
17
+ */
18
+ export interface CacheResult<T = unknown> {
19
+ /** The cached data */
20
+ data: T;
21
+ /** True if within TTL and not dirty */
22
+ fresh: boolean;
23
+ /** Age in milliseconds */
24
+ age: number;
25
+ }
26
+ /**
27
+ * Options for cache_set.
28
+ */
29
+ export interface CacheOptions {
30
+ /** Override default TTL for this entry (milliseconds) */
31
+ ttl?: number;
32
+ /** Mark as dirty immediately */
33
+ dirty?: boolean;
34
+ }
35
+ /**
36
+ * Statistics about cache usage.
37
+ */
38
+ export interface CacheStats {
39
+ /** Total number of cache hits (fresh). */
40
+ hits: number;
41
+ /** Total number of cache misses. */
42
+ misses: number;
43
+ /** Total number of stale hits (served but expired). */
44
+ staleHits: number;
45
+ /** Number of LRU evictions. */
46
+ evictions: number;
47
+ /** Number of entries currently in cache. */
48
+ entries: number;
49
+ /** Estimated total memory usage in bytes. */
50
+ totalSize: number;
51
+ }
52
+ /**
53
+ * Singleton cache for directory listings with TTL and dirty tracking.
54
+ *
55
+ * Generic cache that stores any data type keyed by path. Eliminates redundant
56
+ * API calls by caching directory contents after ls operations.
57
+ *
58
+ * Enhanced features:
59
+ * - TTL-based expiration: Different paths have different TTLs
60
+ * - Dirty flag tracking: Local mutations mark cache as needing refresh
61
+ * - LRU eviction: Bounded memory usage
62
+ * - Optimistic serving: Serve stale cache immediately, refresh in background
63
+ *
64
+ * Usage:
65
+ * ```typescript
66
+ * const cache = listCache_get();
67
+ *
68
+ * // Check cache (returns CacheResult with freshness info)
69
+ * const cached = cache.cache_get("/PUBLIC");
70
+ * if (cached) {
71
+ * console.log(cached.data); // Show immediately
72
+ * if (!cached.fresh) {
73
+ * console.log('Refreshing...');
74
+ * // Fetch fresh data in background
75
+ * }
76
+ * }
77
+ *
78
+ * // Store data
79
+ * cache.cache_set("/PUBLIC", items);
80
+ *
81
+ * // Mark dirty after mutation
82
+ * cache.cache_markDirty("/home/user");
83
+ *
84
+ * // Optimistic update
85
+ * cache.cache_update("/home/user", (items) => items.filter(i => i.name !== 'deleted.txt'));
86
+ * ```
87
+ */
88
+ export declare class ListCache {
89
+ private static instance;
90
+ /** Cache storage: path → entry. */
91
+ private cache;
92
+ /** Maximum cache entries (LRU eviction). */
93
+ private maxEntries;
94
+ /** Default TTL for unconfigured paths (3 minutes). */
95
+ private defaultTTL;
96
+ /** Path-specific TTL configuration. */
97
+ private ttlConfig;
98
+ /** Cache statistics. */
99
+ private stats;
100
+ /**
101
+ * Private constructor to enforce singleton pattern.
102
+ */
103
+ private constructor();
104
+ /**
105
+ * Gets the singleton instance of ListCache.
106
+ *
107
+ * @returns The ListCache singleton instance.
108
+ */
109
+ static instance_get(): ListCache;
110
+ /**
111
+ * Retrieves data from cache with freshness information.
112
+ *
113
+ * @param path - The path to retrieve.
114
+ * @returns CacheResult with freshness info, or null if not cached.
115
+ */
116
+ cache_get<T = unknown>(path: string): CacheResult<T> | null;
117
+ /**
118
+ * Stores data in cache with optional TTL override.
119
+ *
120
+ * @param path - The path to cache.
121
+ * @param data - The data to cache.
122
+ * @param options - Optional TTL and dirty flag.
123
+ */
124
+ cache_set<T = unknown>(path: string, data: T, options?: CacheOptions): void;
125
+ /**
126
+ * Marks a cached path as dirty (needs refresh).
127
+ * Used when local mutations might have changed the data.
128
+ *
129
+ * @param path - The path to mark dirty.
130
+ */
131
+ cache_markDirty(path: string): void;
132
+ /**
133
+ * Optimistically updates cache after a mutation.
134
+ * Example: After rm, remove item from parent directory cache.
135
+ *
136
+ * @param path - The parent directory path.
137
+ * @param updater - Function to transform cached data.
138
+ */
139
+ cache_update<T = unknown>(path: string, updater: (data: T) => T): void;
140
+ /**
141
+ * Invalidates cache for a specific path or clears entire cache.
142
+ * Called by file operations that modify directory contents (mkdir, touch, rm, upload).
143
+ *
144
+ * @param path - Optional specific path to invalidate. If omitted, clears entire cache.
145
+ */
146
+ cache_invalidate(path?: string): void;
147
+ /**
148
+ * @deprecated Use cache without cwd tracking. Cache persists across navigation.
149
+ * This method is kept for backward compatibility but does nothing.
150
+ *
151
+ * @param _newCwd - Ignored.
152
+ */
153
+ cwd_update(_newCwd: string): void;
154
+ /**
155
+ * Gets TTL for a specific path based on configuration.
156
+ *
157
+ * @param path - The path to get TTL for.
158
+ * @returns TTL in milliseconds.
159
+ */
160
+ private ttl_get;
161
+ /**
162
+ * Evicts oldest entries if cache exceeds max size.
163
+ */
164
+ private evict_lru;
165
+ /**
166
+ * Gets cache statistics.
167
+ *
168
+ * @returns Cache statistics including hits, misses, and current state.
169
+ */
170
+ stats_get(): CacheStats;
171
+ /**
172
+ * Resets cache statistics.
173
+ * Useful for testing and monitoring.
174
+ */
175
+ stats_reset(): void;
176
+ }
177
+ /**
178
+ * Convenience function to get the ListCache singleton instance.
179
+ *
180
+ * @returns The ListCache singleton instance.
181
+ */
182
+ export declare function listCache_get(): ListCache;
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ /**
3
+ * @file Enhanced Directory Listing Cache with TTL and dirty tracking.
4
+ *
5
+ * Provides a singleton cache for directory listings to avoid redundant API calls
6
+ * during tab completion and file operations. Features:
7
+ * - TTL-based expiration (different TTLs per path pattern)
8
+ * - Dirty flag tracking (local mutations mark cache as needing refresh)
9
+ * - LRU eviction (bounded memory usage)
10
+ * - Optimistic serving (serve stale cache while refreshing)
11
+ *
12
+ * Generic implementation - stores any data type keyed by path.
13
+ *
14
+ * @module
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.ListCache = void 0;
18
+ exports.listCache_get = listCache_get;
19
+ /**
20
+ * Singleton cache for directory listings with TTL and dirty tracking.
21
+ *
22
+ * Generic cache that stores any data type keyed by path. Eliminates redundant
23
+ * API calls by caching directory contents after ls operations.
24
+ *
25
+ * Enhanced features:
26
+ * - TTL-based expiration: Different paths have different TTLs
27
+ * - Dirty flag tracking: Local mutations mark cache as needing refresh
28
+ * - LRU eviction: Bounded memory usage
29
+ * - Optimistic serving: Serve stale cache immediately, refresh in background
30
+ *
31
+ * Usage:
32
+ * ```typescript
33
+ * const cache = listCache_get();
34
+ *
35
+ * // Check cache (returns CacheResult with freshness info)
36
+ * const cached = cache.cache_get("/PUBLIC");
37
+ * if (cached) {
38
+ * console.log(cached.data); // Show immediately
39
+ * if (!cached.fresh) {
40
+ * console.log('Refreshing...');
41
+ * // Fetch fresh data in background
42
+ * }
43
+ * }
44
+ *
45
+ * // Store data
46
+ * cache.cache_set("/PUBLIC", items);
47
+ *
48
+ * // Mark dirty after mutation
49
+ * cache.cache_markDirty("/home/user");
50
+ *
51
+ * // Optimistic update
52
+ * cache.cache_update("/home/user", (items) => items.filter(i => i.name !== 'deleted.txt'));
53
+ * ```
54
+ */
55
+ class ListCache {
56
+ /**
57
+ * Private constructor to enforce singleton pattern.
58
+ */
59
+ constructor() {
60
+ /** Cache storage: path → entry. */
61
+ this.cache = new Map();
62
+ /** Maximum cache entries (LRU eviction). */
63
+ this.maxEntries = 100;
64
+ /** Default TTL for unconfigured paths (3 minutes). */
65
+ this.defaultTTL = 3 * 60 * 1000;
66
+ /** Path-specific TTL configuration. */
67
+ this.ttlConfig = new Map([
68
+ ['/PUBLIC', 10 * 60 * 1000], // 10 min (stable, public directory)
69
+ ['/home', 5 * 60 * 1000], // 5 min (user home directories)
70
+ ['/bin', 60 * 60 * 1000], // 1 hour (plugins rarely change)
71
+ ['/feeds/*', 5 * 60 * 1000], // 5 min (feed outputs)
72
+ ]);
73
+ /** Cache statistics. */
74
+ this.stats = {
75
+ hits: 0,
76
+ misses: 0,
77
+ staleHits: 0,
78
+ evictions: 0,
79
+ };
80
+ }
81
+ /**
82
+ * Gets the singleton instance of ListCache.
83
+ *
84
+ * @returns The ListCache singleton instance.
85
+ */
86
+ static instance_get() {
87
+ if (!ListCache.instance) {
88
+ ListCache.instance = new ListCache();
89
+ }
90
+ return ListCache.instance;
91
+ }
92
+ /**
93
+ * Retrieves data from cache with freshness information.
94
+ *
95
+ * @param path - The path to retrieve.
96
+ * @returns CacheResult with freshness info, or null if not cached.
97
+ */
98
+ cache_get(path) {
99
+ const entry = this.cache.get(path);
100
+ if (!entry) {
101
+ this.stats.misses++;
102
+ return null;
103
+ }
104
+ // LRU: Move to end (mark as recently used)
105
+ this.cache.delete(path);
106
+ this.cache.set(path, entry);
107
+ // Calculate freshness
108
+ const age = Date.now() - entry.timestamp;
109
+ const fresh = !entry.dirty && age < entry.ttl;
110
+ if (fresh) {
111
+ this.stats.hits++;
112
+ }
113
+ else {
114
+ this.stats.staleHits++;
115
+ }
116
+ return { data: entry.data, fresh, age };
117
+ }
118
+ /**
119
+ * Stores data in cache with optional TTL override.
120
+ *
121
+ * @param path - The path to cache.
122
+ * @param data - The data to cache.
123
+ * @param options - Optional TTL and dirty flag.
124
+ */
125
+ cache_set(path, data, options) {
126
+ // LRU: If exists, delete and re-add (moves to end)
127
+ if (this.cache.has(path)) {
128
+ this.cache.delete(path);
129
+ }
130
+ const ttl = options?.ttl ?? this.ttl_get(path);
131
+ this.cache.set(path, {
132
+ data,
133
+ timestamp: Date.now(),
134
+ dirty: options?.dirty ?? false,
135
+ ttl,
136
+ });
137
+ // LRU eviction if over limit
138
+ this.evict_lru();
139
+ }
140
+ /**
141
+ * Marks a cached path as dirty (needs refresh).
142
+ * Used when local mutations might have changed the data.
143
+ *
144
+ * @param path - The path to mark dirty.
145
+ */
146
+ cache_markDirty(path) {
147
+ const entry = this.cache.get(path);
148
+ if (entry) {
149
+ entry.dirty = true;
150
+ }
151
+ }
152
+ /**
153
+ * Optimistically updates cache after a mutation.
154
+ * Example: After rm, remove item from parent directory cache.
155
+ *
156
+ * @param path - The parent directory path.
157
+ * @param updater - Function to transform cached data.
158
+ */
159
+ cache_update(path, updater) {
160
+ const entry = this.cache.get(path);
161
+ if (entry) {
162
+ entry.data = updater(entry.data);
163
+ entry.timestamp = Date.now(); // Reset timestamp
164
+ entry.dirty = false; // Clean after update
165
+ }
166
+ }
167
+ /**
168
+ * Invalidates cache for a specific path or clears entire cache.
169
+ * Called by file operations that modify directory contents (mkdir, touch, rm, upload).
170
+ *
171
+ * @param path - Optional specific path to invalidate. If omitted, clears entire cache.
172
+ */
173
+ cache_invalidate(path) {
174
+ if (path !== undefined) {
175
+ this.cache.delete(path);
176
+ }
177
+ else {
178
+ this.cache.clear();
179
+ }
180
+ }
181
+ /**
182
+ * @deprecated Use cache without cwd tracking. Cache persists across navigation.
183
+ * This method is kept for backward compatibility but does nothing.
184
+ *
185
+ * @param _newCwd - Ignored.
186
+ */
187
+ cwd_update(_newCwd) {
188
+ // No-op: Cache no longer flushes on directory change
189
+ // Kept for backward compatibility during transition
190
+ }
191
+ /**
192
+ * Gets TTL for a specific path based on configuration.
193
+ *
194
+ * @param path - The path to get TTL for.
195
+ * @returns TTL in milliseconds.
196
+ */
197
+ ttl_get(path) {
198
+ if (this.ttlConfig.has(path)) {
199
+ return this.ttlConfig.get(path);
200
+ }
201
+ for (const [pattern, ttl] of this.ttlConfig) {
202
+ if (pattern.includes('*')) {
203
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
204
+ if (regex.test(path)) {
205
+ return ttl;
206
+ }
207
+ }
208
+ }
209
+ return this.defaultTTL;
210
+ }
211
+ /**
212
+ * Evicts oldest entries if cache exceeds max size.
213
+ */
214
+ evict_lru() {
215
+ while (this.cache.size > this.maxEntries) {
216
+ const oldestKey = this.cache.keys().next().value;
217
+ if (oldestKey !== undefined) {
218
+ this.cache.delete(oldestKey);
219
+ this.stats.evictions++;
220
+ }
221
+ else {
222
+ break; // Should never happen, but safety check
223
+ }
224
+ }
225
+ }
226
+ /**
227
+ * Gets cache statistics.
228
+ *
229
+ * @returns Cache statistics including hits, misses, and current state.
230
+ */
231
+ stats_get() {
232
+ let totalSize = 0;
233
+ for (const entry of this.cache.values()) {
234
+ // Rough estimate: JSON string length
235
+ totalSize += JSON.stringify(entry.data).length;
236
+ }
237
+ return {
238
+ hits: this.stats.hits,
239
+ misses: this.stats.misses,
240
+ staleHits: this.stats.staleHits,
241
+ evictions: this.stats.evictions,
242
+ entries: this.cache.size,
243
+ totalSize,
244
+ };
245
+ }
246
+ /**
247
+ * Resets cache statistics.
248
+ * Useful for testing and monitoring.
249
+ */
250
+ stats_reset() {
251
+ this.stats.hits = 0;
252
+ this.stats.misses = 0;
253
+ this.stats.staleHits = 0;
254
+ this.stats.evictions = 0;
255
+ }
256
+ }
257
+ exports.ListCache = ListCache;
258
+ /**
259
+ * Convenience function to get the ListCache singleton instance.
260
+ *
261
+ * @returns The ListCache singleton instance.
262
+ */
263
+ function listCache_get() {
264
+ return ListCache.instance_get();
265
+ }
266
+ //# sourceMappingURL=listCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listCache.js","sourceRoot":"","sources":["../../src/cache/listCache.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAgVH,sCAEC;AA/QD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAa,SAAS;IA4BpB;;OAEG;IACH;QA5BA,mCAAmC;QAC3B,UAAK,GAAqC,IAAI,GAAG,EAAE,CAAC;QAE5D,4CAA4C;QACpC,eAAU,GAAW,GAAG,CAAC;QAEjC,sDAAsD;QAC9C,eAAU,GAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAE3C,uCAAuC;QAC/B,cAAS,GAAwB,IAAI,GAAG,CAAC;YAC/C,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,EAAM,oCAAoC;YACrE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAU,gCAAgC;YAClE,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,EAAU,iCAAiC;YACnE,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAO,uBAAuB;SAC1D,CAAC,CAAC;QAEH,wBAAwB;QAChB,UAAK,GAAG;YACd,IAAI,EAAE,CAAC;YACP,MAAM,EAAE,CAAC;YACT,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,CAAC;SACb,CAAC;IAKqB,CAAC;IAExB;;;;OAIG;IACH,MAAM,CAAC,YAAY;QACjB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,GAAG,IAAI,SAAS,EAAE,CAAC;QACvC,CAAC;QACD,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAc,IAAY;QACjC,MAAM,KAAK,GAAoC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEpE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,2CAA2C;QAC3C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAE5B,sBAAsB;QACtB,MAAM,GAAG,GAAW,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC;QACjD,MAAM,KAAK,GAAY,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;QAEvD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACzB,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAS,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC/C,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAc,IAAY,EAAE,IAAO,EAAE,OAAsB;QAClE,mDAAmD;QACnD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAED,MAAM,GAAG,GAAW,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEvD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE;YACnB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK;YAC9B,GAAG;SACJ,CAAC,CAAC;QAEH,6BAA6B;QAC7B,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,eAAe,CAAC,IAAY;QAC1B,MAAM,KAAK,GAAoC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,YAAY,CAAc,IAAY,EAAE,OAAuB;QAC7D,MAAM,KAAK,GAAoC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAS,CAAC,CAAC;YACtC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAE,kBAAkB;YACjD,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAY,qBAAqB;QACvD,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,IAAa;QAC5B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,OAAe;QACxB,qDAAqD;QACrD,oDAAoD;IACtD,CAAC;IAED;;;;;OAKG;IACK,OAAO,CAAC,IAAY;QAC1B,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QACnC,CAAC;QAED,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5C,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,KAAK,GAAW,IAAI,MAAM,CAAC,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;gBAC3E,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrB,OAAO,GAAG,CAAC;gBACb,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,SAAS;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,SAAS,GAAuB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACrE,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC7B,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAE,wCAAwC;YAClD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,SAAS;QACP,IAAI,SAAS,GAAW,CAAC,CAAC;QAC1B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,qCAAqC;YACrC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QACjD,CAAC;QAED,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACrB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;YACzB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;YAC/B,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;YAC/B,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACxB,SAAS;SACV,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;IAC3B,CAAC;CACF;AAlOD,8BAkOC;AAED;;;;GAIG;AACH,SAAgB,aAAa;IAC3B,OAAO,SAAS,CAAC,YAAY,EAAE,CAAC;AAClC,CAAC"}