pcu 0.2.6

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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +478 -0
  3. package/bin/pcu.js +15 -0
  4. package/dist/application/services/CatalogUpdateService.d.ts +190 -0
  5. package/dist/application/services/CatalogUpdateService.d.ts.map +1 -0
  6. package/dist/application/services/CatalogUpdateService.js +521 -0
  7. package/dist/application/services/CatalogUpdateService.js.map +1 -0
  8. package/dist/application/services/WorkspaceService.d.ts +139 -0
  9. package/dist/application/services/WorkspaceService.d.ts.map +1 -0
  10. package/dist/application/services/WorkspaceService.js +340 -0
  11. package/dist/application/services/WorkspaceService.js.map +1 -0
  12. package/dist/cli/commands/CheckCommand.d.ts +41 -0
  13. package/dist/cli/commands/CheckCommand.d.ts.map +1 -0
  14. package/dist/cli/commands/CheckCommand.js +168 -0
  15. package/dist/cli/commands/CheckCommand.js.map +1 -0
  16. package/dist/cli/commands/UpdateCommand.d.ts +69 -0
  17. package/dist/cli/commands/UpdateCommand.d.ts.map +1 -0
  18. package/dist/cli/commands/UpdateCommand.js +361 -0
  19. package/dist/cli/commands/UpdateCommand.js.map +1 -0
  20. package/dist/cli/formatters/OutputFormatter.d.ts +99 -0
  21. package/dist/cli/formatters/OutputFormatter.d.ts.map +1 -0
  22. package/dist/cli/formatters/OutputFormatter.js +551 -0
  23. package/dist/cli/formatters/OutputFormatter.js.map +1 -0
  24. package/dist/cli/index.d.ts +12 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/cli/index.js +271 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/cli/options/GlobalOptions.d.ts +117 -0
  29. package/dist/cli/options/GlobalOptions.d.ts.map +1 -0
  30. package/dist/cli/options/GlobalOptions.js +278 -0
  31. package/dist/cli/options/GlobalOptions.js.map +1 -0
  32. package/dist/cli/options/index.d.ts +5 -0
  33. package/dist/cli/options/index.d.ts.map +1 -0
  34. package/dist/cli/options/index.js +5 -0
  35. package/dist/cli/options/index.js.map +1 -0
  36. package/dist/cli/validators/CommandValidator.d.ts +60 -0
  37. package/dist/cli/validators/CommandValidator.d.ts.map +1 -0
  38. package/dist/cli/validators/CommandValidator.js +319 -0
  39. package/dist/cli/validators/CommandValidator.js.map +1 -0
  40. package/dist/cli/validators/index.d.ts +5 -0
  41. package/dist/cli/validators/index.d.ts.map +1 -0
  42. package/dist/cli/validators/index.js +5 -0
  43. package/dist/cli/validators/index.js.map +1 -0
  44. package/dist/common/config/Config.d.ts +142 -0
  45. package/dist/common/config/Config.d.ts.map +1 -0
  46. package/dist/common/config/Config.js +355 -0
  47. package/dist/common/config/Config.js.map +1 -0
  48. package/dist/common/config/index.d.ts +6 -0
  49. package/dist/common/config/index.d.ts.map +1 -0
  50. package/dist/common/config/index.js +6 -0
  51. package/dist/common/config/index.js.map +1 -0
  52. package/dist/common/logger/Logger.d.ts +110 -0
  53. package/dist/common/logger/Logger.d.ts.map +1 -0
  54. package/dist/common/logger/Logger.js +289 -0
  55. package/dist/common/logger/Logger.js.map +1 -0
  56. package/dist/common/logger/index.d.ts +6 -0
  57. package/dist/common/logger/index.d.ts.map +1 -0
  58. package/dist/common/logger/index.js +6 -0
  59. package/dist/common/logger/index.js.map +1 -0
  60. package/dist/common/types/cli.d.ts +265 -0
  61. package/dist/common/types/cli.d.ts.map +1 -0
  62. package/dist/common/types/cli.js +5 -0
  63. package/dist/common/types/cli.js.map +1 -0
  64. package/dist/common/types/core.d.ts +270 -0
  65. package/dist/common/types/core.d.ts.map +1 -0
  66. package/dist/common/types/core.js +32 -0
  67. package/dist/common/types/core.js.map +1 -0
  68. package/dist/common/types/index.d.ts +8 -0
  69. package/dist/common/types/index.d.ts.map +1 -0
  70. package/dist/common/types/index.js +8 -0
  71. package/dist/common/types/index.js.map +1 -0
  72. package/dist/common/utils/async.d.ts +74 -0
  73. package/dist/common/utils/async.d.ts.map +1 -0
  74. package/dist/common/utils/async.js +228 -0
  75. package/dist/common/utils/async.js.map +1 -0
  76. package/dist/common/utils/format.d.ts +32 -0
  77. package/dist/common/utils/format.d.ts.map +1 -0
  78. package/dist/common/utils/format.js +121 -0
  79. package/dist/common/utils/format.js.map +1 -0
  80. package/dist/common/utils/git.d.ts +44 -0
  81. package/dist/common/utils/git.d.ts.map +1 -0
  82. package/dist/common/utils/git.js +147 -0
  83. package/dist/common/utils/git.js.map +1 -0
  84. package/dist/common/utils/index.d.ts +11 -0
  85. package/dist/common/utils/index.d.ts.map +1 -0
  86. package/dist/common/utils/index.js +11 -0
  87. package/dist/common/utils/index.js.map +1 -0
  88. package/dist/common/utils/string.d.ts +56 -0
  89. package/dist/common/utils/string.d.ts.map +1 -0
  90. package/dist/common/utils/string.js +134 -0
  91. package/dist/common/utils/string.js.map +1 -0
  92. package/dist/common/utils/validation.d.ts +88 -0
  93. package/dist/common/utils/validation.d.ts.map +1 -0
  94. package/dist/common/utils/validation.js +281 -0
  95. package/dist/common/utils/validation.js.map +1 -0
  96. package/dist/domain/entities/Catalog.d.ts +117 -0
  97. package/dist/domain/entities/Catalog.d.ts.map +1 -0
  98. package/dist/domain/entities/Catalog.js +240 -0
  99. package/dist/domain/entities/Catalog.js.map +1 -0
  100. package/dist/domain/entities/Package.d.ts +143 -0
  101. package/dist/domain/entities/Package.d.ts.map +1 -0
  102. package/dist/domain/entities/Package.js +272 -0
  103. package/dist/domain/entities/Package.js.map +1 -0
  104. package/dist/domain/entities/Workspace.d.ts +95 -0
  105. package/dist/domain/entities/Workspace.d.ts.map +1 -0
  106. package/dist/domain/entities/Workspace.js +173 -0
  107. package/dist/domain/entities/Workspace.js.map +1 -0
  108. package/dist/domain/repositories/WorkspaceRepository.d.ts +41 -0
  109. package/dist/domain/repositories/WorkspaceRepository.d.ts.map +1 -0
  110. package/dist/domain/repositories/WorkspaceRepository.js +8 -0
  111. package/dist/domain/repositories/WorkspaceRepository.js.map +1 -0
  112. package/dist/domain/value-objects/CatalogCollection.d.ts +106 -0
  113. package/dist/domain/value-objects/CatalogCollection.d.ts.map +1 -0
  114. package/dist/domain/value-objects/CatalogCollection.js +230 -0
  115. package/dist/domain/value-objects/CatalogCollection.js.map +1 -0
  116. package/dist/domain/value-objects/PackageCollection.d.ts +122 -0
  117. package/dist/domain/value-objects/PackageCollection.d.ts.map +1 -0
  118. package/dist/domain/value-objects/PackageCollection.js +263 -0
  119. package/dist/domain/value-objects/PackageCollection.js.map +1 -0
  120. package/dist/domain/value-objects/Version.d.ts +141 -0
  121. package/dist/domain/value-objects/Version.d.ts.map +1 -0
  122. package/dist/domain/value-objects/Version.js +268 -0
  123. package/dist/domain/value-objects/Version.js.map +1 -0
  124. package/dist/domain/value-objects/WorkspaceConfig.d.ts +144 -0
  125. package/dist/domain/value-objects/WorkspaceConfig.d.ts.map +1 -0
  126. package/dist/domain/value-objects/WorkspaceConfig.js +357 -0
  127. package/dist/domain/value-objects/WorkspaceConfig.js.map +1 -0
  128. package/dist/domain/value-objects/WorkspaceId.d.ts +51 -0
  129. package/dist/domain/value-objects/WorkspaceId.d.ts.map +1 -0
  130. package/dist/domain/value-objects/WorkspaceId.js +104 -0
  131. package/dist/domain/value-objects/WorkspaceId.js.map +1 -0
  132. package/dist/domain/value-objects/WorkspacePath.d.ts +75 -0
  133. package/dist/domain/value-objects/WorkspacePath.d.ts.map +1 -0
  134. package/dist/domain/value-objects/WorkspacePath.js +128 -0
  135. package/dist/domain/value-objects/WorkspacePath.js.map +1 -0
  136. package/dist/infrastructure/cache/Cache.d.ts +161 -0
  137. package/dist/infrastructure/cache/Cache.d.ts.map +1 -0
  138. package/dist/infrastructure/cache/Cache.js +398 -0
  139. package/dist/infrastructure/cache/Cache.js.map +1 -0
  140. package/dist/infrastructure/cache/index.d.ts +6 -0
  141. package/dist/infrastructure/cache/index.d.ts.map +1 -0
  142. package/dist/infrastructure/cache/index.js +6 -0
  143. package/dist/infrastructure/cache/index.js.map +1 -0
  144. package/dist/infrastructure/external-services/NpmRegistryService.d.ts +106 -0
  145. package/dist/infrastructure/external-services/NpmRegistryService.d.ts.map +1 -0
  146. package/dist/infrastructure/external-services/NpmRegistryService.js +305 -0
  147. package/dist/infrastructure/external-services/NpmRegistryService.js.map +1 -0
  148. package/dist/infrastructure/file-system/FileSystemService.d.ts +120 -0
  149. package/dist/infrastructure/file-system/FileSystemService.d.ts.map +1 -0
  150. package/dist/infrastructure/file-system/FileSystemService.js +663 -0
  151. package/dist/infrastructure/file-system/FileSystemService.js.map +1 -0
  152. package/dist/infrastructure/repositories/FileWorkspaceRepository.d.ts +57 -0
  153. package/dist/infrastructure/repositories/FileWorkspaceRepository.d.ts.map +1 -0
  154. package/dist/infrastructure/repositories/FileWorkspaceRepository.js +179 -0
  155. package/dist/infrastructure/repositories/FileWorkspaceRepository.js.map +1 -0
  156. package/package.json +127 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * WorkspacePath Value Object
3
+ *
4
+ * Represents a file system path to a pnpm workspace.
5
+ * This is an immutable value object that validates and normalizes workspace paths.
6
+ */
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ export class WorkspacePath {
10
+ value;
11
+ constructor(value) {
12
+ this.value = value;
13
+ }
14
+ /**
15
+ * Create a WorkspacePath from a string
16
+ */
17
+ static fromString(pathString) {
18
+ if (!pathString || pathString.trim().length === 0) {
19
+ throw new Error('WorkspacePath cannot be empty');
20
+ }
21
+ // Normalize the path
22
+ const normalized = path.resolve(pathString.trim());
23
+ return new WorkspacePath(normalized);
24
+ }
25
+ /**
26
+ * Create a WorkspacePath from the current working directory
27
+ */
28
+ static current() {
29
+ return new WorkspacePath(process.cwd());
30
+ }
31
+ /**
32
+ * Create a WorkspacePath from file URL (useful for ES modules)
33
+ */
34
+ static fromFileURL(fileUrl) {
35
+ const filePath = fileURLToPath(fileUrl);
36
+ const directory = path.dirname(filePath);
37
+ return new WorkspacePath(directory);
38
+ }
39
+ /**
40
+ * Get the absolute path as a string
41
+ */
42
+ toString() {
43
+ return this.value;
44
+ }
45
+ /**
46
+ * Get the directory name (last part of the path)
47
+ */
48
+ getDirectoryName() {
49
+ return path.basename(this.value);
50
+ }
51
+ /**
52
+ * Join with another path segment
53
+ */
54
+ join(...segments) {
55
+ const joined = path.join(this.value, ...segments);
56
+ return new WorkspacePath(joined);
57
+ }
58
+ /**
59
+ * Get the parent directory
60
+ */
61
+ getParent() {
62
+ const parent = path.dirname(this.value);
63
+ return new WorkspacePath(parent);
64
+ }
65
+ /**
66
+ * Check if this path is a subdirectory of another path
67
+ */
68
+ isSubdirectoryOf(other) {
69
+ const relativePath = path.relative(other.value, this.value);
70
+ return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
71
+ }
72
+ /**
73
+ * Get relative path from another WorkspacePath
74
+ */
75
+ relativeTo(other) {
76
+ return path.relative(other.value, this.value);
77
+ }
78
+ /**
79
+ * Check equality with another WorkspacePath
80
+ */
81
+ equals(other) {
82
+ return path.resolve(this.value) === path.resolve(other.value);
83
+ }
84
+ /**
85
+ * Get the value for serialization
86
+ */
87
+ getValue() {
88
+ return this.value;
89
+ }
90
+ /**
91
+ * Convert to JSON representation
92
+ */
93
+ toJSON() {
94
+ return this.value;
95
+ }
96
+ /**
97
+ * Create from JSON representation
98
+ */
99
+ static fromJSON(json) {
100
+ return WorkspacePath.fromString(json);
101
+ }
102
+ /**
103
+ * Check if this path exists (requires async validation in infrastructure layer)
104
+ */
105
+ async exists() {
106
+ try {
107
+ const fs = await import('fs/promises');
108
+ await fs.access(this.value);
109
+ return true;
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ }
115
+ /**
116
+ * Get the path to pnpm-workspace.yaml
117
+ */
118
+ getPnpmWorkspaceConfigPath() {
119
+ return this.join('pnpm-workspace.yaml');
120
+ }
121
+ /**
122
+ * Get the path to package.json
123
+ */
124
+ getPackageJsonPath() {
125
+ return this.join('package.json');
126
+ }
127
+ }
128
+ //# sourceMappingURL=WorkspacePath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkspacePath.js","sourceRoot":"","sources":["../../../src/domain/value-objects/WorkspacePath.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Cache System
3
+ *
4
+ * Provides caching capabilities for NPM registry responses and other expensive operations.
5
+ * Supports both in-memory and file-based caching with TTL and size limits.
6
+ */
7
+ export interface CacheEntry<T = any> {
8
+ key: string;
9
+ value: T;
10
+ timestamp: number;
11
+ ttl: number;
12
+ size: number;
13
+ }
14
+ export interface CacheOptions {
15
+ ttl?: number;
16
+ maxSize?: number;
17
+ maxEntries?: number;
18
+ persistToDisk?: boolean;
19
+ cacheDir?: string;
20
+ }
21
+ export interface CacheStats {
22
+ totalEntries: number;
23
+ totalSize: number;
24
+ hitRate: number;
25
+ missRate: number;
26
+ hits: number;
27
+ misses: number;
28
+ }
29
+ export declare class Cache<T = any> {
30
+ private entries;
31
+ private stats;
32
+ private options;
33
+ constructor(name: string, options?: CacheOptions);
34
+ /**
35
+ * Get value from cache
36
+ */
37
+ get(key: string): T | undefined;
38
+ /**
39
+ * Set value in cache
40
+ */
41
+ set(key: string, value: T, ttl?: number): void;
42
+ /**
43
+ * Check if key exists in cache
44
+ */
45
+ has(key: string): boolean;
46
+ /**
47
+ * Delete entry from cache
48
+ */
49
+ delete(key: string): boolean;
50
+ /**
51
+ * Clear all cache entries
52
+ */
53
+ clear(): void;
54
+ /**
55
+ * Get cache statistics
56
+ */
57
+ getStats(): CacheStats;
58
+ /**
59
+ * Get or set with factory function
60
+ */
61
+ getOrSet(key: string, factory: () => Promise<T> | T, ttl?: number): Promise<T>;
62
+ /**
63
+ * Cleanup expired entries
64
+ */
65
+ private cleanup;
66
+ /**
67
+ * Ensure cache capacity doesn't exceed limits
68
+ */
69
+ private ensureCapacity;
70
+ /**
71
+ * Evict oldest entry
72
+ */
73
+ private evictOldest;
74
+ /**
75
+ * Get total cache size
76
+ */
77
+ private getTotalSize;
78
+ /**
79
+ * Estimate size of value in bytes
80
+ */
81
+ private estimateSize;
82
+ /**
83
+ * Load cache from disk
84
+ */
85
+ private loadFromDisk;
86
+ /**
87
+ * Save entry to disk
88
+ */
89
+ private saveToDisk;
90
+ /**
91
+ * Delete entry from disk
92
+ */
93
+ private deleteFromDisk;
94
+ /**
95
+ * Clear disk cache
96
+ */
97
+ private clearDisk;
98
+ /**
99
+ * Update disk index
100
+ */
101
+ private updateDiskIndex;
102
+ /**
103
+ * Get filename for cache key
104
+ */
105
+ private getFilename;
106
+ }
107
+ /**
108
+ * Registry-specific cache for NPM API responses
109
+ */
110
+ export declare class RegistryCache extends Cache<any> {
111
+ constructor(options?: CacheOptions);
112
+ /**
113
+ * Cache package info
114
+ */
115
+ setPackageInfo(packageName: string, info: any, ttl?: number): void;
116
+ /**
117
+ * Get cached package info
118
+ */
119
+ getPackageInfo(packageName: string): any | undefined;
120
+ /**
121
+ * Cache version list
122
+ */
123
+ setVersions(packageName: string, versions: string[], ttl?: number): void;
124
+ /**
125
+ * Get cached versions
126
+ */
127
+ getVersions(packageName: string): string[] | undefined;
128
+ /**
129
+ * Cache security report
130
+ */
131
+ setSecurityReport(packageName: string, version: string, report: any, ttl?: number): void;
132
+ /**
133
+ * Get cached security report
134
+ */
135
+ getSecurityReport(packageName: string, version: string): any | undefined;
136
+ }
137
+ /**
138
+ * Workspace-specific cache for file system operations
139
+ */
140
+ export declare class WorkspaceCache extends Cache<any> {
141
+ constructor(options?: CacheOptions);
142
+ /**
143
+ * Cache workspace info
144
+ */
145
+ setWorkspaceInfo(workspacePath: string, info: any, ttl?: number): void;
146
+ /**
147
+ * Get cached workspace info
148
+ */
149
+ getWorkspaceInfo(workspacePath: string): any | undefined;
150
+ /**
151
+ * Cache package.json content
152
+ */
153
+ setPackageJson(filePath: string, content: any, ttl?: number): void;
154
+ /**
155
+ * Get cached package.json
156
+ */
157
+ getPackageJson(filePath: string): any | undefined;
158
+ }
159
+ export declare const registryCache: RegistryCache;
160
+ export declare const workspaceCache: WorkspaceCache;
161
+ //# sourceMappingURL=Cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cache.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/cache/Cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,398 @@
1
+ /**
2
+ * Cache System
3
+ *
4
+ * Provides caching capabilities for NPM registry responses and other expensive operations.
5
+ * Supports both in-memory and file-based caching with TTL and size limits.
6
+ */
7
+ import { writeFileSync, readFileSync, existsSync, mkdirSync, unlinkSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ import { createHash } from 'crypto';
11
+ export class Cache {
12
+ entries = new Map();
13
+ stats = {
14
+ hits: 0,
15
+ misses: 0,
16
+ };
17
+ options;
18
+ constructor(name, options = {}) {
19
+ this.options = {
20
+ ttl: options.ttl || 3600000, // 1 hour default
21
+ maxSize: options.maxSize || 50 * 1024 * 1024, // 50MB default
22
+ maxEntries: options.maxEntries || 1000,
23
+ persistToDisk: options.persistToDisk || false,
24
+ cacheDir: options.cacheDir || join(homedir(), '.pcu', 'cache', name),
25
+ };
26
+ if (this.options.persistToDisk) {
27
+ this.loadFromDisk();
28
+ }
29
+ // Setup cleanup interval
30
+ setInterval(() => this.cleanup(), 300000); // Clean every 5 minutes
31
+ }
32
+ /**
33
+ * Get value from cache
34
+ */
35
+ get(key) {
36
+ const entry = this.entries.get(key);
37
+ if (!entry) {
38
+ this.stats.misses++;
39
+ return undefined;
40
+ }
41
+ // Check if entry has expired
42
+ if (Date.now() - entry.timestamp > entry.ttl) {
43
+ this.entries.delete(key);
44
+ this.stats.misses++;
45
+ return undefined;
46
+ }
47
+ this.stats.hits++;
48
+ return entry.value;
49
+ }
50
+ /**
51
+ * Set value in cache
52
+ */
53
+ set(key, value, ttl) {
54
+ const entryTtl = ttl || this.options.ttl;
55
+ const size = this.estimateSize(value);
56
+ const entry = {
57
+ key,
58
+ value,
59
+ timestamp: Date.now(),
60
+ ttl: entryTtl,
61
+ size,
62
+ };
63
+ // Remove old entry if exists
64
+ if (this.entries.has(key)) {
65
+ this.entries.delete(key);
66
+ }
67
+ // Check size limits before adding
68
+ this.ensureCapacity(size);
69
+ this.entries.set(key, entry);
70
+ if (this.options.persistToDisk) {
71
+ this.saveToDisk(key, entry);
72
+ }
73
+ }
74
+ /**
75
+ * Check if key exists in cache
76
+ */
77
+ has(key) {
78
+ const entry = this.entries.get(key);
79
+ if (!entry) {
80
+ return false;
81
+ }
82
+ // Check if expired
83
+ if (Date.now() - entry.timestamp > entry.ttl) {
84
+ this.entries.delete(key);
85
+ return false;
86
+ }
87
+ return true;
88
+ }
89
+ /**
90
+ * Delete entry from cache
91
+ */
92
+ delete(key) {
93
+ const deleted = this.entries.delete(key);
94
+ if (deleted && this.options.persistToDisk) {
95
+ this.deleteFromDisk(key);
96
+ }
97
+ return deleted;
98
+ }
99
+ /**
100
+ * Clear all cache entries
101
+ */
102
+ clear() {
103
+ this.entries.clear();
104
+ this.stats.hits = 0;
105
+ this.stats.misses = 0;
106
+ if (this.options.persistToDisk) {
107
+ this.clearDisk();
108
+ }
109
+ }
110
+ /**
111
+ * Get cache statistics
112
+ */
113
+ getStats() {
114
+ const total = this.stats.hits + this.stats.misses;
115
+ return {
116
+ totalEntries: this.entries.size,
117
+ totalSize: this.getTotalSize(),
118
+ hitRate: total > 0 ? this.stats.hits / total : 0,
119
+ missRate: total > 0 ? this.stats.misses / total : 0,
120
+ hits: this.stats.hits,
121
+ misses: this.stats.misses,
122
+ };
123
+ }
124
+ /**
125
+ * Get or set with factory function
126
+ */
127
+ async getOrSet(key, factory, ttl) {
128
+ const cached = this.get(key);
129
+ if (cached !== undefined) {
130
+ return cached;
131
+ }
132
+ const value = await factory();
133
+ this.set(key, value, ttl);
134
+ return value;
135
+ }
136
+ /**
137
+ * Cleanup expired entries
138
+ */
139
+ cleanup() {
140
+ const now = Date.now();
141
+ const expiredKeys = [];
142
+ for (const [key, entry] of this.entries) {
143
+ if (now - entry.timestamp > entry.ttl) {
144
+ expiredKeys.push(key);
145
+ }
146
+ }
147
+ for (const key of expiredKeys) {
148
+ this.delete(key);
149
+ }
150
+ }
151
+ /**
152
+ * Ensure cache capacity doesn't exceed limits
153
+ */
154
+ ensureCapacity(newEntrySize) {
155
+ // Check entry count limit
156
+ while (this.entries.size >= this.options.maxEntries) {
157
+ this.evictOldest();
158
+ }
159
+ // Check size limit
160
+ while (this.getTotalSize() + newEntrySize > this.options.maxSize) {
161
+ this.evictOldest();
162
+ }
163
+ }
164
+ /**
165
+ * Evict oldest entry
166
+ */
167
+ evictOldest() {
168
+ let oldestKey;
169
+ let oldestTimestamp = Date.now();
170
+ for (const [key, entry] of this.entries) {
171
+ if (entry.timestamp < oldestTimestamp) {
172
+ oldestTimestamp = entry.timestamp;
173
+ oldestKey = key;
174
+ }
175
+ }
176
+ if (oldestKey) {
177
+ this.delete(oldestKey);
178
+ }
179
+ }
180
+ /**
181
+ * Get total cache size
182
+ */
183
+ getTotalSize() {
184
+ let totalSize = 0;
185
+ for (const entry of this.entries.values()) {
186
+ totalSize += entry.size;
187
+ }
188
+ return totalSize;
189
+ }
190
+ /**
191
+ * Estimate size of value in bytes
192
+ */
193
+ estimateSize(value) {
194
+ try {
195
+ return JSON.stringify(value).length * 2; // Rough UTF-16 estimate
196
+ }
197
+ catch {
198
+ return 1000; // Default estimate for non-serializable values
199
+ }
200
+ }
201
+ /**
202
+ * Load cache from disk
203
+ */
204
+ loadFromDisk() {
205
+ try {
206
+ if (!existsSync(this.options.cacheDir)) {
207
+ return;
208
+ }
209
+ const indexPath = join(this.options.cacheDir, 'index.json');
210
+ if (!existsSync(indexPath)) {
211
+ return;
212
+ }
213
+ const indexContent = readFileSync(indexPath, 'utf-8');
214
+ const index = JSON.parse(indexContent);
215
+ for (const key of index.keys || []) {
216
+ try {
217
+ const entryPath = join(this.options.cacheDir, this.getFilename(key));
218
+ if (existsSync(entryPath)) {
219
+ const entryContent = readFileSync(entryPath, 'utf-8');
220
+ const entry = JSON.parse(entryContent);
221
+ // Check if entry is still valid
222
+ if (Date.now() - entry.timestamp <= entry.ttl) {
223
+ this.entries.set(key, entry);
224
+ }
225
+ }
226
+ }
227
+ catch {
228
+ // Skip corrupted entries
229
+ }
230
+ }
231
+ }
232
+ catch {
233
+ // Ignore disk loading errors
234
+ }
235
+ }
236
+ /**
237
+ * Save entry to disk
238
+ */
239
+ saveToDisk(key, entry) {
240
+ try {
241
+ if (!existsSync(this.options.cacheDir)) {
242
+ mkdirSync(this.options.cacheDir, { recursive: true });
243
+ }
244
+ const entryPath = join(this.options.cacheDir, this.getFilename(key));
245
+ writeFileSync(entryPath, JSON.stringify(entry), 'utf-8');
246
+ // Update index
247
+ this.updateDiskIndex();
248
+ }
249
+ catch {
250
+ // Ignore disk saving errors
251
+ }
252
+ }
253
+ /**
254
+ * Delete entry from disk
255
+ */
256
+ deleteFromDisk(key) {
257
+ try {
258
+ const entryPath = join(this.options.cacheDir, this.getFilename(key));
259
+ if (existsSync(entryPath)) {
260
+ unlinkSync(entryPath);
261
+ }
262
+ this.updateDiskIndex();
263
+ }
264
+ catch {
265
+ // Ignore disk deletion errors
266
+ }
267
+ }
268
+ /**
269
+ * Clear disk cache
270
+ */
271
+ clearDisk() {
272
+ try {
273
+ if (existsSync(this.options.cacheDir)) {
274
+ const fs = require('fs');
275
+ fs.rmSync(this.options.cacheDir, { recursive: true, force: true });
276
+ }
277
+ }
278
+ catch {
279
+ // Ignore disk clearing errors
280
+ }
281
+ }
282
+ /**
283
+ * Update disk index
284
+ */
285
+ updateDiskIndex() {
286
+ try {
287
+ const indexPath = join(this.options.cacheDir, 'index.json');
288
+ const index = {
289
+ keys: Array.from(this.entries.keys()),
290
+ lastUpdated: Date.now(),
291
+ };
292
+ writeFileSync(indexPath, JSON.stringify(index), 'utf-8');
293
+ }
294
+ catch {
295
+ // Ignore index update errors
296
+ }
297
+ }
298
+ /**
299
+ * Get filename for cache key
300
+ */
301
+ getFilename(key) {
302
+ // Use hash to create safe filename
303
+ const hash = createHash('md5').update(key).digest('hex');
304
+ return `${hash}.json`;
305
+ }
306
+ }
307
+ /**
308
+ * Registry-specific cache for NPM API responses
309
+ */
310
+ export class RegistryCache extends Cache {
311
+ constructor(options = {}) {
312
+ super('registry', {
313
+ ttl: 3600000, // 1 hour
314
+ maxSize: 10 * 1024 * 1024, // 10MB
315
+ maxEntries: 500,
316
+ persistToDisk: true,
317
+ ...options,
318
+ });
319
+ }
320
+ /**
321
+ * Cache package info
322
+ */
323
+ setPackageInfo(packageName, info, ttl) {
324
+ this.set(`package:${packageName}`, info, ttl);
325
+ }
326
+ /**
327
+ * Get cached package info
328
+ */
329
+ getPackageInfo(packageName) {
330
+ return this.get(`package:${packageName}`);
331
+ }
332
+ /**
333
+ * Cache version list
334
+ */
335
+ setVersions(packageName, versions, ttl) {
336
+ this.set(`versions:${packageName}`, versions, ttl);
337
+ }
338
+ /**
339
+ * Get cached versions
340
+ */
341
+ getVersions(packageName) {
342
+ return this.get(`versions:${packageName}`);
343
+ }
344
+ /**
345
+ * Cache security report
346
+ */
347
+ setSecurityReport(packageName, version, report, ttl) {
348
+ this.set(`security:${packageName}:${version}`, report, ttl);
349
+ }
350
+ /**
351
+ * Get cached security report
352
+ */
353
+ getSecurityReport(packageName, version) {
354
+ return this.get(`security:${packageName}:${version}`);
355
+ }
356
+ }
357
+ /**
358
+ * Workspace-specific cache for file system operations
359
+ */
360
+ export class WorkspaceCache extends Cache {
361
+ constructor(options = {}) {
362
+ super('workspace', {
363
+ ttl: 300000, // 5 minutes (shorter TTL for file system)
364
+ maxSize: 5 * 1024 * 1024, // 5MB
365
+ maxEntries: 200,
366
+ persistToDisk: false, // Don't persist workspace cache
367
+ ...options,
368
+ });
369
+ }
370
+ /**
371
+ * Cache workspace info
372
+ */
373
+ setWorkspaceInfo(workspacePath, info, ttl) {
374
+ this.set(`workspace:${workspacePath}`, info, ttl);
375
+ }
376
+ /**
377
+ * Get cached workspace info
378
+ */
379
+ getWorkspaceInfo(workspacePath) {
380
+ return this.get(`workspace:${workspacePath}`);
381
+ }
382
+ /**
383
+ * Cache package.json content
384
+ */
385
+ setPackageJson(filePath, content, ttl) {
386
+ this.set(`package-json:${filePath}`, content, ttl);
387
+ }
388
+ /**
389
+ * Get cached package.json
390
+ */
391
+ getPackageJson(filePath) {
392
+ return this.get(`package-json:${filePath}`);
393
+ }
394
+ }
395
+ // Export singleton instances
396
+ export const registryCache = new RegistryCache();
397
+ export const workspaceCache = new WorkspaceCache();
398
+ //# sourceMappingURL=Cache.js.map