@objectstack/core 4.0.4 → 4.1.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 (75) hide show
  1. package/README.md +95 -10
  2. package/dist/index.cjs +172 -507
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +24 -223
  5. package/dist/index.d.ts +24 -223
  6. package/dist/index.js +178 -505
  7. package/dist/index.js.map +1 -1
  8. package/dist/logger.cjs +177 -0
  9. package/dist/logger.cjs.map +1 -0
  10. package/dist/logger.d.cts +26 -0
  11. package/dist/logger.d.ts +26 -0
  12. package/dist/logger.js +158 -0
  13. package/dist/logger.js.map +1 -0
  14. package/package.json +36 -15
  15. package/.turbo/turbo-build.log +0 -22
  16. package/ADVANCED_FEATURES.md +0 -380
  17. package/API_REGISTRY.md +0 -392
  18. package/CHANGELOG.md +0 -472
  19. package/PHASE2_IMPLEMENTATION.md +0 -388
  20. package/REFACTORING_SUMMARY.md +0 -40
  21. package/examples/api-registry-example.ts +0 -559
  22. package/examples/kernel-features-example.ts +0 -311
  23. package/examples/phase2-integration.ts +0 -357
  24. package/src/api-registry-plugin.test.ts +0 -393
  25. package/src/api-registry-plugin.ts +0 -89
  26. package/src/api-registry.test.ts +0 -1089
  27. package/src/api-registry.ts +0 -739
  28. package/src/contracts/data-engine.ts +0 -57
  29. package/src/contracts/http-server.ts +0 -151
  30. package/src/contracts/logger.ts +0 -72
  31. package/src/dependency-resolver.test.ts +0 -287
  32. package/src/dependency-resolver.ts +0 -390
  33. package/src/fallbacks/fallbacks.test.ts +0 -281
  34. package/src/fallbacks/index.ts +0 -26
  35. package/src/fallbacks/memory-cache.ts +0 -34
  36. package/src/fallbacks/memory-i18n.ts +0 -112
  37. package/src/fallbacks/memory-job.ts +0 -23
  38. package/src/fallbacks/memory-metadata.ts +0 -50
  39. package/src/fallbacks/memory-queue.ts +0 -28
  40. package/src/health-monitor.test.ts +0 -81
  41. package/src/health-monitor.ts +0 -318
  42. package/src/hot-reload.ts +0 -382
  43. package/src/index.ts +0 -50
  44. package/src/kernel-base.ts +0 -273
  45. package/src/kernel.test.ts +0 -624
  46. package/src/kernel.ts +0 -631
  47. package/src/lite-kernel.test.ts +0 -248
  48. package/src/lite-kernel.ts +0 -137
  49. package/src/logger.test.ts +0 -116
  50. package/src/logger.ts +0 -355
  51. package/src/namespace-resolver.test.ts +0 -130
  52. package/src/namespace-resolver.ts +0 -188
  53. package/src/package-manager.test.ts +0 -225
  54. package/src/package-manager.ts +0 -428
  55. package/src/plugin-loader.test.ts +0 -421
  56. package/src/plugin-loader.ts +0 -484
  57. package/src/qa/adapter.ts +0 -16
  58. package/src/qa/http-adapter.ts +0 -116
  59. package/src/qa/index.ts +0 -5
  60. package/src/qa/runner.ts +0 -189
  61. package/src/security/index.ts +0 -50
  62. package/src/security/permission-manager.test.ts +0 -256
  63. package/src/security/permission-manager.ts +0 -338
  64. package/src/security/plugin-config-validator.test.ts +0 -276
  65. package/src/security/plugin-config-validator.ts +0 -193
  66. package/src/security/plugin-permission-enforcer.test.ts +0 -251
  67. package/src/security/plugin-permission-enforcer.ts +0 -436
  68. package/src/security/plugin-signature-verifier.ts +0 -403
  69. package/src/security/sandbox-runtime.ts +0 -462
  70. package/src/security/security-scanner.ts +0 -367
  71. package/src/types.ts +0 -120
  72. package/src/utils/env.test.ts +0 -62
  73. package/src/utils/env.ts +0 -53
  74. package/tsconfig.json +0 -10
  75. package/vitest.config.ts +0 -10
@@ -1,225 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { PackageManager } from './package-manager.js';
3
- import { createLogger } from './logger.js';
4
-
5
- describe('PackageManager', () => {
6
- let manager: PackageManager;
7
-
8
- beforeEach(() => {
9
- const logger = createLogger({ level: 'silent' });
10
- manager = new PackageManager(logger, { platformVersion: '3.0.0' });
11
- });
12
-
13
- describe('install', () => {
14
- it('should install a package successfully', async () => {
15
- const result = await manager.install('pkg-a', '1.0.0', {
16
- objects: { task: { label: 'Task' } },
17
- });
18
-
19
- expect(result.success).toBe(true);
20
- expect(result.packageId).toBe('pkg-a');
21
- expect(result.version).toBe('1.0.0');
22
- expect(manager.getPackage('pkg-a')).toBeDefined();
23
- expect(manager.getPackage('pkg-a')?.status).toBe('installed');
24
- });
25
-
26
- it('should reject already installed package', async () => {
27
- await manager.install('pkg-a', '1.0.0', {});
28
- const result = await manager.install('pkg-a', '1.0.0', {});
29
-
30
- expect(result.success).toBe(false);
31
- expect(result.errorMessage).toContain('already installed');
32
- });
33
-
34
- it('should detect namespace conflicts', async () => {
35
- await manager.install('pkg-a', '1.0.0', {
36
- objects: { task: {} },
37
- });
38
-
39
- const result = await manager.install('pkg-b', '1.0.0', {
40
- objects: { task: {} },
41
- });
42
-
43
- expect(result.success).toBe(false);
44
- expect(result.namespaceConflicts).toHaveLength(1);
45
- expect(result.namespaceConflicts[0].namespace).toBe('objects.task');
46
- expect(result.namespaceConflicts[0].existingPackageId).toBe('pkg-a');
47
- });
48
-
49
- it('should reject incompatible platform version', async () => {
50
- const result = await manager.install('pkg-a', '1.0.0', {
51
- engine: { objectstack: '>=4.0.0' },
52
- });
53
-
54
- expect(result.success).toBe(false);
55
- expect(result.errorMessage).toContain('platform');
56
- });
57
-
58
- it('should reject missing dependencies', async () => {
59
- const result = await manager.install('pkg-a', '1.0.0', {
60
- dependencies: { 'pkg-b': '^1.0.0' },
61
- });
62
-
63
- expect(result.success).toBe(false);
64
- expect(result.errorMessage).toContain('Missing dependencies');
65
- });
66
-
67
- it('should succeed when dependencies are installed', async () => {
68
- await manager.install('pkg-b', '1.0.0', {});
69
- const result = await manager.install('pkg-a', '1.0.0', {
70
- dependencies: { 'pkg-b': '^1.0.0' },
71
- });
72
-
73
- expect(result.success).toBe(true);
74
- expect(result.installedDependencies).toContain('pkg-b');
75
- });
76
- });
77
-
78
- describe('uninstall', () => {
79
- it('should uninstall a package', async () => {
80
- await manager.install('pkg-a', '1.0.0', {});
81
- const result = await manager.uninstall('pkg-a');
82
-
83
- expect(result.success).toBe(true);
84
- expect(manager.getPackage('pkg-a')).toBeUndefined();
85
- });
86
-
87
- it('should prevent uninstalling if dependents exist', async () => {
88
- await manager.install('pkg-a', '1.0.0', {});
89
- await manager.install('pkg-b', '1.0.0', {
90
- dependencies: { 'pkg-a': '^1.0.0' },
91
- });
92
-
93
- const result = await manager.uninstall('pkg-a');
94
- expect(result.success).toBe(false);
95
- expect(result.errorMessage).toContain('depended upon');
96
- });
97
-
98
- it('should reject uninstalling unknown package', async () => {
99
- const result = await manager.uninstall('unknown');
100
- expect(result.success).toBe(false);
101
- });
102
- });
103
-
104
- describe('upgrade', () => {
105
- it('should upgrade a package and create snapshot', async () => {
106
- await manager.install('pkg-a', '1.0.0', {
107
- objects: { task: {} },
108
- });
109
-
110
- const result = await manager.upgrade('pkg-a', '2.0.0', {
111
- objects: { task: {}, project: {} },
112
- });
113
-
114
- expect(result.success).toBe(true);
115
- expect(result.fromVersion).toBe('1.0.0');
116
- expect(result.toVersion).toBe('2.0.0');
117
- expect(result.snapshot.previousVersion).toBe('1.0.0');
118
- expect(manager.getPackage('pkg-a')?.version).toBe('2.0.0');
119
- });
120
-
121
- it('should reject upgrade for uninstalled package', async () => {
122
- const result = await manager.upgrade('unknown', '2.0.0', {});
123
- expect(result.success).toBe(false);
124
- expect(result.errorMessage).toContain('not installed');
125
- });
126
-
127
- it('should detect namespace conflicts during upgrade', async () => {
128
- await manager.install('pkg-a', '1.0.0', { objects: { task: {} } });
129
- await manager.install('pkg-b', '1.0.0', { objects: { project: {} } });
130
-
131
- // pkg-a upgrade tries to add objects.project which is owned by pkg-b
132
- const result = await manager.upgrade('pkg-a', '2.0.0', {
133
- objects: { task: {}, project: {} },
134
- });
135
-
136
- expect(result.success).toBe(false);
137
- expect(result.errorMessage).toContain('Namespace conflicts');
138
- });
139
-
140
- it('should reject platform-incompatible upgrade', async () => {
141
- await manager.install('pkg-a', '1.0.0', {});
142
-
143
- const result = await manager.upgrade('pkg-a', '2.0.0', {
144
- engine: { objectstack: '>=5.0.0' },
145
- });
146
-
147
- expect(result.success).toBe(false);
148
- expect(result.errorMessage).toContain('platform');
149
- });
150
- });
151
-
152
- describe('rollback', () => {
153
- it('should rollback to pre-upgrade state', async () => {
154
- await manager.install('pkg-a', '1.0.0', {
155
- objects: { task: {} },
156
- });
157
- await manager.upgrade('pkg-a', '2.0.0', {
158
- objects: { task: {}, project: {} },
159
- });
160
-
161
- const result = await manager.rollback('pkg-a');
162
- expect(result.success).toBe(true);
163
- expect(result.restoredVersion).toBe('1.0.0');
164
- expect(manager.getPackage('pkg-a')?.version).toBe('1.0.0');
165
- });
166
-
167
- it('should reject rollback without snapshot', async () => {
168
- await manager.install('pkg-a', '1.0.0', {});
169
- const result = await manager.rollback('pkg-a');
170
-
171
- expect(result.success).toBe(false);
172
- expect(result.errorMessage).toContain('No upgrade snapshot');
173
- });
174
- });
175
-
176
- describe('listPackages', () => {
177
- it('should list all installed packages', async () => {
178
- await manager.install('pkg-a', '1.0.0', {});
179
- await manager.install('pkg-b', '2.0.0', {});
180
-
181
- const list = manager.listPackages();
182
- expect(list).toHaveLength(2);
183
- expect(list.map(p => p.packageId)).toContain('pkg-a');
184
- expect(list.map(p => p.packageId)).toContain('pkg-b');
185
- });
186
- });
187
-
188
- describe('checkNamespaces', () => {
189
- it('should check namespace availability', async () => {
190
- await manager.install('pkg-a', '1.0.0', {
191
- objects: { task: {} },
192
- });
193
-
194
- const result = manager.checkNamespaces('pkg-b', {
195
- objects: { task: {} },
196
- });
197
-
198
- expect(result.available).toBe(false);
199
- expect(result.conflicts).toHaveLength(1);
200
- });
201
-
202
- it('should report available when no conflicts', () => {
203
- const result = manager.checkNamespaces('pkg-a', {
204
- objects: { task: {} },
205
- });
206
-
207
- expect(result.available).toBe(true);
208
- expect(result.conflicts).toHaveLength(0);
209
- });
210
- });
211
-
212
- describe('resolveDependencies', () => {
213
- it('should resolve dependencies in topological order', () => {
214
- const packages = new Map([
215
- ['a', { dependencies: [] as string[] }],
216
- ['b', { dependencies: ['a'] }],
217
- ['c', { dependencies: ['a', 'b'] }],
218
- ]);
219
-
220
- const order = manager.resolveDependencies(packages);
221
- expect(order.indexOf('a')).toBeLessThan(order.indexOf('b'));
222
- expect(order.indexOf('b')).toBeLessThan(order.indexOf('c'));
223
- });
224
- });
225
- });
@@ -1,428 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import type { ObjectLogger } from './logger.js';
4
- import { DependencyResolver, SemanticVersionManager } from './dependency-resolver.js';
5
- import { NamespaceResolver } from './namespace-resolver.js';
6
-
7
- /**
8
- * Installed package record in the runtime registry.
9
- */
10
- export interface InstalledPackageRecord {
11
- /** Package identifier */
12
- packageId: string;
13
- /** Package version */
14
- version: string;
15
- /** Package manifest */
16
- manifest: Record<string, unknown>;
17
- /** Installation timestamp */
18
- installedAt: string;
19
- /** Current status */
20
- status: 'installed' | 'disabled' | 'installing' | 'upgrading' | 'uninstalling' | 'error';
21
- /** Namespaces registered by this package */
22
- namespaces: string[];
23
- /** Dependencies of this package */
24
- dependencies: string[];
25
- }
26
-
27
- /**
28
- * Snapshot of a package's state before upgrade (for rollback).
29
- */
30
- export interface PackageSnapshot {
31
- /** Package identifier */
32
- packageId: string;
33
- /** Version before upgrade */
34
- previousVersion: string;
35
- /** Full manifest before upgrade */
36
- previousManifest: Record<string, unknown>;
37
- /** Namespaces before upgrade */
38
- previousNamespaces: string[];
39
- /** Original installation timestamp */
40
- installedAt: string;
41
- /** Snapshot timestamp */
42
- createdAt: string;
43
- }
44
-
45
- /**
46
- * Result of a package installation attempt.
47
- */
48
- export interface InstallResult {
49
- success: boolean;
50
- packageId: string;
51
- version: string;
52
- installedDependencies: string[];
53
- namespaceConflicts: Array<{ namespace: string; existingPackageId: string }>;
54
- errorMessage?: string;
55
- }
56
-
57
- /**
58
- * Result of an upgrade attempt.
59
- */
60
- export interface UpgradeResult {
61
- success: boolean;
62
- packageId: string;
63
- fromVersion: string;
64
- toVersion: string;
65
- snapshot: PackageSnapshot;
66
- errorMessage?: string;
67
- }
68
-
69
- /**
70
- * Result of a rollback attempt.
71
- */
72
- export interface RollbackResult {
73
- success: boolean;
74
- packageId: string;
75
- restoredVersion: string;
76
- errorMessage?: string;
77
- }
78
-
79
- /**
80
- * Package Manager
81
- *
82
- * Runtime implementation for the full package lifecycle:
83
- * install → upgrade → rollback → uninstall.
84
- *
85
- * Consumes the protocol schemas defined in @objectstack/spec:
86
- * - DependencyResolutionResultSchema
87
- * - NamespaceConflictErrorSchema
88
- * - UpgradePlanSchema / UpgradeSnapshotSchema
89
- * - PackageArtifactSchema
90
- *
91
- * Coordinates with:
92
- * - DependencyResolver for topological ordering and conflict detection
93
- * - NamespaceResolver for metadata collision prevention
94
- */
95
- export class PackageManager {
96
- private logger: ObjectLogger;
97
- private packages: Map<string, InstalledPackageRecord> = new Map();
98
- private snapshots: Map<string, PackageSnapshot> = new Map();
99
- private dependencyResolver: DependencyResolver;
100
- private namespaceResolver: NamespaceResolver;
101
- private platformVersion: string;
102
-
103
- constructor(
104
- logger: ObjectLogger,
105
- options: { platformVersion?: string } = {},
106
- ) {
107
- this.logger = logger.child({ component: 'PackageManager' });
108
- this.dependencyResolver = new DependencyResolver(logger);
109
- this.namespaceResolver = new NamespaceResolver(logger);
110
- this.platformVersion = options.platformVersion || '3.0.0';
111
- }
112
-
113
- /**
114
- * Install a package with full dependency resolution and namespace checking.
115
- */
116
- async install(
117
- packageId: string,
118
- version: string,
119
- manifest: Record<string, unknown>,
120
- ): Promise<InstallResult> {
121
- this.logger.info('Installing package', { packageId, version });
122
-
123
- // 1. Check if already installed
124
- if (this.packages.has(packageId)) {
125
- const existing = this.packages.get(packageId)!;
126
- if (existing.status === 'installed') {
127
- return {
128
- success: false,
129
- packageId,
130
- version,
131
- installedDependencies: [],
132
- namespaceConflicts: [],
133
- errorMessage: `Package ${packageId}@${existing.version} is already installed. Use upgrade instead.`,
134
- };
135
- }
136
- }
137
-
138
- // 2. Check platform compatibility
139
- const engine = (manifest as any).engine?.objectstack as string | undefined;
140
- if (engine) {
141
- const platformSemver = SemanticVersionManager.parse(this.platformVersion);
142
- if (!SemanticVersionManager.satisfies(platformSemver, engine)) {
143
- return {
144
- success: false,
145
- packageId,
146
- version,
147
- installedDependencies: [],
148
- namespaceConflicts: [],
149
- errorMessage: `Package requires platform ${engine}, but current platform is v${this.platformVersion}`,
150
- };
151
- }
152
- }
153
-
154
- // 3. Check namespace conflicts
155
- const namespaces = this.namespaceResolver.extractNamespaces(manifest);
156
- const nsCheck = this.namespaceResolver.checkAvailability(packageId, namespaces);
157
- if (!nsCheck.available) {
158
- return {
159
- success: false,
160
- packageId,
161
- version,
162
- installedDependencies: [],
163
- namespaceConflicts: nsCheck.conflicts.map(c => ({
164
- namespace: c.namespace,
165
- existingPackageId: c.existingPackageId,
166
- })),
167
- errorMessage: `Namespace conflicts detected: ${nsCheck.conflicts.map(c => c.namespace).join(', ')}`,
168
- };
169
- }
170
-
171
- // 4. Resolve dependencies
172
- const deps = (manifest as any).dependencies as Record<string, string> | undefined;
173
- const depNames = deps ? Object.keys(deps) : [];
174
- const missingDeps = depNames.filter(d => !this.packages.has(d));
175
- if (missingDeps.length > 0) {
176
- return {
177
- success: false,
178
- packageId,
179
- version,
180
- installedDependencies: [],
181
- namespaceConflicts: [],
182
- errorMessage: `Missing dependencies: ${missingDeps.join(', ')}`,
183
- };
184
- }
185
-
186
- // 5. Register package
187
- this.packages.set(packageId, {
188
- packageId,
189
- version,
190
- manifest,
191
- installedAt: new Date().toISOString(),
192
- status: 'installed',
193
- namespaces,
194
- dependencies: depNames,
195
- });
196
-
197
- // 6. Register namespaces
198
- this.namespaceResolver.register(packageId, namespaces);
199
-
200
- this.logger.info('Package installed', { packageId, version, namespaces: namespaces.length });
201
-
202
- return {
203
- success: true,
204
- packageId,
205
- version,
206
- installedDependencies: depNames,
207
- namespaceConflicts: [],
208
- };
209
- }
210
-
211
- /**
212
- * Uninstall a package, checking for dependents first.
213
- */
214
- async uninstall(packageId: string): Promise<{ success: boolean; errorMessage?: string }> {
215
- const pkg = this.packages.get(packageId);
216
- if (!pkg) {
217
- return { success: false, errorMessage: `Package ${packageId} is not installed` };
218
- }
219
-
220
- // Check if other packages depend on this one
221
- const dependents: string[] = [];
222
- for (const [id, record] of this.packages) {
223
- if (id !== packageId && record.dependencies.includes(packageId)) {
224
- dependents.push(id);
225
- }
226
- }
227
-
228
- if (dependents.length > 0) {
229
- return {
230
- success: false,
231
- errorMessage: `Cannot uninstall ${packageId}: depended upon by ${dependents.join(', ')}`,
232
- };
233
- }
234
-
235
- // Remove namespaces and package
236
- this.namespaceResolver.unregister(packageId);
237
- this.packages.delete(packageId);
238
- this.snapshots.delete(packageId);
239
-
240
- this.logger.info('Package uninstalled', { packageId });
241
- return { success: true };
242
- }
243
-
244
- /**
245
- * Upgrade a package: snapshot → update → register.
246
- */
247
- async upgrade(
248
- packageId: string,
249
- newVersion: string,
250
- newManifest: Record<string, unknown>,
251
- ): Promise<UpgradeResult> {
252
- const existing = this.packages.get(packageId);
253
- if (!existing) {
254
- return {
255
- success: false,
256
- packageId,
257
- fromVersion: '',
258
- toVersion: newVersion,
259
- snapshot: { packageId, previousVersion: '', previousManifest: {}, previousNamespaces: [], installedAt: '', createdAt: new Date().toISOString() },
260
- errorMessage: `Package ${packageId} is not installed`,
261
- };
262
- }
263
-
264
- // 1. Create snapshot for rollback
265
- const snapshot: PackageSnapshot = {
266
- packageId,
267
- previousVersion: existing.version,
268
- previousManifest: existing.manifest,
269
- previousNamespaces: [...existing.namespaces],
270
- installedAt: existing.installedAt,
271
- createdAt: new Date().toISOString(),
272
- };
273
- this.snapshots.set(packageId, snapshot);
274
-
275
- // 2. Check platform compatibility
276
- const engine = (newManifest as any).engine?.objectstack as string | undefined;
277
- if (engine) {
278
- const platformSemver = SemanticVersionManager.parse(this.platformVersion);
279
- if (!SemanticVersionManager.satisfies(platformSemver, engine)) {
280
- return {
281
- success: false,
282
- packageId,
283
- fromVersion: existing.version,
284
- toVersion: newVersion,
285
- snapshot,
286
- errorMessage: `New version requires platform ${engine}, current is v${this.platformVersion}`,
287
- };
288
- }
289
- }
290
-
291
- // 3. Check namespace changes
292
- const newNamespaces = this.namespaceResolver.extractNamespaces(newManifest);
293
- // Temporarily remove old namespaces to check new ones
294
- this.namespaceResolver.unregister(packageId);
295
- const nsCheck = this.namespaceResolver.checkAvailability(packageId, newNamespaces);
296
- if (!nsCheck.available) {
297
- // Restore old namespaces on failure
298
- this.namespaceResolver.register(packageId, existing.namespaces);
299
- return {
300
- success: false,
301
- packageId,
302
- fromVersion: existing.version,
303
- toVersion: newVersion,
304
- snapshot,
305
- errorMessage: `Namespace conflicts in new version: ${nsCheck.conflicts.map(c => c.namespace).join(', ')}`,
306
- };
307
- }
308
-
309
- // 4. Register new namespaces and update record
310
- this.namespaceResolver.register(packageId, newNamespaces);
311
- const deps = (newManifest as any).dependencies as Record<string, string> | undefined;
312
-
313
- this.packages.set(packageId, {
314
- packageId,
315
- version: newVersion,
316
- manifest: newManifest,
317
- installedAt: existing.installedAt,
318
- status: 'installed',
319
- namespaces: newNamespaces,
320
- dependencies: deps ? Object.keys(deps) : [],
321
- });
322
-
323
- this.logger.info('Package upgraded', { packageId, from: existing.version, to: newVersion });
324
-
325
- return {
326
- success: true,
327
- packageId,
328
- fromVersion: existing.version,
329
- toVersion: newVersion,
330
- snapshot,
331
- };
332
- }
333
-
334
- /**
335
- * Rollback a package to its pre-upgrade snapshot.
336
- */
337
- async rollback(packageId: string): Promise<RollbackResult> {
338
- const snapshot = this.snapshots.get(packageId);
339
- if (!snapshot) {
340
- return {
341
- success: false,
342
- packageId,
343
- restoredVersion: '',
344
- errorMessage: `No upgrade snapshot found for ${packageId}`,
345
- };
346
- }
347
-
348
- // Restore previous state
349
- this.namespaceResolver.unregister(packageId);
350
- this.namespaceResolver.register(packageId, snapshot.previousNamespaces);
351
-
352
- const deps = (snapshot.previousManifest as any).dependencies as Record<string, string> | undefined;
353
- this.packages.set(packageId, {
354
- packageId,
355
- version: snapshot.previousVersion,
356
- manifest: snapshot.previousManifest,
357
- installedAt: snapshot.installedAt,
358
- status: 'installed',
359
- namespaces: snapshot.previousNamespaces,
360
- dependencies: deps ? Object.keys(deps) : [],
361
- });
362
-
363
- this.snapshots.delete(packageId);
364
-
365
- this.logger.info('Package rolled back', { packageId, to: snapshot.previousVersion });
366
-
367
- return {
368
- success: true,
369
- packageId,
370
- restoredVersion: snapshot.previousVersion,
371
- };
372
- }
373
-
374
- /**
375
- * Get an installed package record.
376
- */
377
- getPackage(packageId: string): InstalledPackageRecord | undefined {
378
- return this.packages.get(packageId);
379
- }
380
-
381
- /**
382
- * List all installed packages.
383
- */
384
- listPackages(): InstalledPackageRecord[] {
385
- return Array.from(this.packages.values());
386
- }
387
-
388
- /**
389
- * Resolve dependencies for a set of packages.
390
- */
391
- resolveDependencies(
392
- packages: Map<string, { version?: string; dependencies?: string[] }>,
393
- ): string[] {
394
- return this.dependencyResolver.resolve(packages);
395
- }
396
-
397
- /**
398
- * Check namespace availability for a package's metadata.
399
- */
400
- checkNamespaces(packageId: string, config: Record<string, unknown>): {
401
- available: boolean;
402
- conflicts: Array<{ namespace: string; existingPackageId: string }>;
403
- } {
404
- const namespaces = this.namespaceResolver.extractNamespaces(config);
405
- const result = this.namespaceResolver.checkAvailability(packageId, namespaces);
406
- return {
407
- available: result.available,
408
- conflicts: result.conflicts.map(c => ({
409
- namespace: c.namespace,
410
- existingPackageId: c.existingPackageId,
411
- })),
412
- };
413
- }
414
-
415
- /**
416
- * Get the namespace resolver instance.
417
- */
418
- getNamespaceResolver(): NamespaceResolver {
419
- return this.namespaceResolver;
420
- }
421
-
422
- /**
423
- * Get a snapshot for a given package (if available).
424
- */
425
- getSnapshot(packageId: string): PackageSnapshot | undefined {
426
- return this.snapshots.get(packageId);
427
- }
428
- }