@soulcraft/brainy 5.2.1 → 5.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.
- package/CHANGELOG.md +5 -0
- package/dist/augmentations/versioningAugmentation.d.ts +121 -0
- package/dist/augmentations/versioningAugmentation.js +418 -0
- package/dist/brainy.d.ts +28 -0
- package/dist/brainy.js +33 -1
- package/dist/versioning/VersionDiff.d.ts +112 -0
- package/dist/versioning/VersionDiff.js +320 -0
- package/dist/versioning/VersionIndex.d.ts +126 -0
- package/dist/versioning/VersionIndex.js +275 -0
- package/dist/versioning/VersionManager.d.ts +195 -0
- package/dist/versioning/VersionManager.js +352 -0
- package/dist/versioning/VersionStorage.d.ts +101 -0
- package/dist/versioning/VersionStorage.js +222 -0
- package/dist/versioning/VersioningAPI.d.ts +347 -0
- package/dist/versioning/VersioningAPI.js +432 -0
- package/dist/vfs/VirtualFileSystem.js +8 -4
- package/dist/vfs/types.d.ts +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [5.3.0](https://github.com/soulcraftlabs/brainy/compare/v5.2.1...v5.3.0) (2025-11-04)
|
|
6
|
+
|
|
7
|
+
- feat: add entity versioning system with critical bug fixes (v5.3.0) (c488fa8)
|
|
8
|
+
|
|
9
|
+
|
|
5
10
|
### [5.2.0](https://github.com/soulcraftlabs/brainy/compare/v5.1.2...v5.2.0) (2025-11-03)
|
|
6
11
|
|
|
7
12
|
- fix: update VFS test for v5.2.0 BlobStorage architecture (b3e3e5c)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versioning Augmentation (v5.3.0)
|
|
3
|
+
*
|
|
4
|
+
* Provides automatic entity versioning with configurable policies:
|
|
5
|
+
* - Auto-save on update()
|
|
6
|
+
* - Entity filtering
|
|
7
|
+
* - Retention policies
|
|
8
|
+
* - Event hooks
|
|
9
|
+
*
|
|
10
|
+
* NO MOCKS - Production implementation
|
|
11
|
+
*/
|
|
12
|
+
import { BaseAugmentation } from './brainyAugmentation.js';
|
|
13
|
+
import { AugmentationManifest } from './manifest.js';
|
|
14
|
+
import type { SaveVersionOptions } from '../versioning/VersionManager.js';
|
|
15
|
+
export interface VersioningAugmentationConfig {
|
|
16
|
+
/** Enable auto-versioning */
|
|
17
|
+
enabled?: boolean;
|
|
18
|
+
/** Auto-save on update() operations */
|
|
19
|
+
onUpdate?: boolean;
|
|
20
|
+
/** Auto-save on add() operations (rarely needed) */
|
|
21
|
+
onAdd?: boolean;
|
|
22
|
+
/** Entity ID patterns to version (glob patterns) */
|
|
23
|
+
entities?: string[];
|
|
24
|
+
/** Entity ID patterns to exclude (glob patterns) */
|
|
25
|
+
excludeEntities?: string[];
|
|
26
|
+
/** Entity types to version */
|
|
27
|
+
types?: string[];
|
|
28
|
+
/** Entity types to exclude */
|
|
29
|
+
excludeTypes?: string[];
|
|
30
|
+
/** Retention policy: Keep N recent versions per entity */
|
|
31
|
+
keepRecent?: number;
|
|
32
|
+
/** Retention policy: Keep versions newer than timestamp */
|
|
33
|
+
keepAfter?: number;
|
|
34
|
+
/** Retention policy: Keep tagged versions (default: true) */
|
|
35
|
+
keepTagged?: boolean;
|
|
36
|
+
/** Tag prefix for auto-generated versions (default: 'auto-') */
|
|
37
|
+
tagPrefix?: string;
|
|
38
|
+
/** Auto-prune old versions after save */
|
|
39
|
+
autoPrune?: boolean;
|
|
40
|
+
/** Prune interval in milliseconds (default: 1 hour) */
|
|
41
|
+
pruneInterval?: number;
|
|
42
|
+
/** Event hooks */
|
|
43
|
+
hooks?: {
|
|
44
|
+
/** Called before saving version */
|
|
45
|
+
beforeSave?: (entityId: string, options: SaveVersionOptions) => Promise<SaveVersionOptions | null>;
|
|
46
|
+
/** Called after saving version */
|
|
47
|
+
afterSave?: (entityId: string, version: any) => Promise<void>;
|
|
48
|
+
/** Called before pruning */
|
|
49
|
+
beforePrune?: (entityId: string) => Promise<boolean>;
|
|
50
|
+
/** Called after pruning */
|
|
51
|
+
afterPrune?: (entityId: string, deleted: number) => Promise<void>;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Versioning Augmentation
|
|
56
|
+
*
|
|
57
|
+
* Automatically versions entities based on configurable policies.
|
|
58
|
+
*/
|
|
59
|
+
export declare class VersioningAugmentation extends BaseAugmentation {
|
|
60
|
+
readonly name = "versioning";
|
|
61
|
+
readonly timing: "after";
|
|
62
|
+
readonly metadata: "readonly";
|
|
63
|
+
operations: any;
|
|
64
|
+
readonly priority = 50;
|
|
65
|
+
readonly category: "core";
|
|
66
|
+
readonly description = "Automatic entity versioning with configurable retention policies";
|
|
67
|
+
private versioningAPI?;
|
|
68
|
+
private brain?;
|
|
69
|
+
private pruneTimer?;
|
|
70
|
+
private versionCount;
|
|
71
|
+
constructor(config?: VersioningAugmentationConfig);
|
|
72
|
+
getManifest(): AugmentationManifest;
|
|
73
|
+
onAttach(brain: any): Promise<void>;
|
|
74
|
+
onDetach(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Execute method (required by BaseAugmentation)
|
|
77
|
+
*/
|
|
78
|
+
execute(operation: string, params: any[], context: any): Promise<any>;
|
|
79
|
+
/**
|
|
80
|
+
* After operation hook - auto-save versions
|
|
81
|
+
*/
|
|
82
|
+
after(operation: string, params: any[], result: any): Promise<any>;
|
|
83
|
+
/**
|
|
84
|
+
* Extract entity ID from operation params
|
|
85
|
+
*/
|
|
86
|
+
private extractEntityId;
|
|
87
|
+
/**
|
|
88
|
+
* Check if entity should be versioned based on filters
|
|
89
|
+
*/
|
|
90
|
+
private shouldVersionEntity;
|
|
91
|
+
/**
|
|
92
|
+
* Simple glob pattern matching
|
|
93
|
+
*/
|
|
94
|
+
private matchPattern;
|
|
95
|
+
/**
|
|
96
|
+
* Prune old versions for an entity
|
|
97
|
+
*/
|
|
98
|
+
private pruneEntity;
|
|
99
|
+
/**
|
|
100
|
+
* Start auto-prune timer
|
|
101
|
+
*/
|
|
102
|
+
private startAutoPrune;
|
|
103
|
+
/**
|
|
104
|
+
* Prune all versioned entities
|
|
105
|
+
*/
|
|
106
|
+
private pruneAllEntities;
|
|
107
|
+
/**
|
|
108
|
+
* Get augmentation statistics
|
|
109
|
+
*/
|
|
110
|
+
getStats(): {
|
|
111
|
+
enabled: boolean;
|
|
112
|
+
versionsCreated: number;
|
|
113
|
+
entitiesPattern: string[];
|
|
114
|
+
excludePattern: string[];
|
|
115
|
+
retention: number;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Factory function for easy augmentation creation
|
|
120
|
+
*/
|
|
121
|
+
export declare function createVersioningAugmentation(config?: VersioningAugmentationConfig): VersioningAugmentation;
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versioning Augmentation (v5.3.0)
|
|
3
|
+
*
|
|
4
|
+
* Provides automatic entity versioning with configurable policies:
|
|
5
|
+
* - Auto-save on update()
|
|
6
|
+
* - Entity filtering
|
|
7
|
+
* - Retention policies
|
|
8
|
+
* - Event hooks
|
|
9
|
+
*
|
|
10
|
+
* NO MOCKS - Production implementation
|
|
11
|
+
*/
|
|
12
|
+
import { BaseAugmentation } from './brainyAugmentation.js';
|
|
13
|
+
/**
|
|
14
|
+
* Versioning Augmentation
|
|
15
|
+
*
|
|
16
|
+
* Automatically versions entities based on configurable policies.
|
|
17
|
+
*/
|
|
18
|
+
export class VersioningAugmentation extends BaseAugmentation {
|
|
19
|
+
constructor(config = {}) {
|
|
20
|
+
super(config);
|
|
21
|
+
this.name = 'versioning';
|
|
22
|
+
this.timing = 'after'; // Run after operations complete
|
|
23
|
+
this.metadata = 'readonly';
|
|
24
|
+
this.operations = ['update', 'add']; // Version on update/add
|
|
25
|
+
this.priority = 50; // Medium priority
|
|
26
|
+
// Augmentation metadata
|
|
27
|
+
this.category = 'core';
|
|
28
|
+
this.description = 'Automatic entity versioning with configurable retention policies';
|
|
29
|
+
this.versionCount = 0;
|
|
30
|
+
// Merge with defaults
|
|
31
|
+
this.config = {
|
|
32
|
+
enabled: config.enabled ?? true,
|
|
33
|
+
onUpdate: config.onUpdate ?? true,
|
|
34
|
+
onAdd: config.onAdd ?? false,
|
|
35
|
+
entities: config.entities ?? ['*'], // Version all entities by default
|
|
36
|
+
excludeEntities: config.excludeEntities ?? ['_version:*'], // Exclude version metadata entities
|
|
37
|
+
types: config.types ?? [], // Empty = all types
|
|
38
|
+
excludeTypes: config.excludeTypes ?? [], // No need to exclude types (versions use 'state' type)
|
|
39
|
+
keepRecent: config.keepRecent ?? 10,
|
|
40
|
+
keepTagged: config.keepTagged ?? true,
|
|
41
|
+
tagPrefix: config.tagPrefix ?? 'auto-',
|
|
42
|
+
autoPrune: config.autoPrune ?? true,
|
|
43
|
+
pruneInterval: config.pruneInterval ?? 60 * 60 * 1000, // 1 hour
|
|
44
|
+
hooks: config.hooks ?? {}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
getManifest() {
|
|
48
|
+
return {
|
|
49
|
+
id: 'versioning',
|
|
50
|
+
name: 'Entity Versioning',
|
|
51
|
+
version: '5.3.0',
|
|
52
|
+
description: 'Automatic entity versioning with retention policies',
|
|
53
|
+
longDescription: 'Provides automatic versioning of entities on update/add operations with configurable retention policies, entity filtering, and event hooks.',
|
|
54
|
+
category: 'storage',
|
|
55
|
+
configSchema: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
enabled: {
|
|
59
|
+
type: 'boolean',
|
|
60
|
+
default: true,
|
|
61
|
+
description: 'Enable automatic versioning'
|
|
62
|
+
},
|
|
63
|
+
onUpdate: {
|
|
64
|
+
type: 'boolean',
|
|
65
|
+
default: true,
|
|
66
|
+
description: 'Auto-save version on update()'
|
|
67
|
+
},
|
|
68
|
+
onAdd: {
|
|
69
|
+
type: 'boolean',
|
|
70
|
+
default: false,
|
|
71
|
+
description: 'Auto-save version on add()'
|
|
72
|
+
},
|
|
73
|
+
entities: {
|
|
74
|
+
type: 'array',
|
|
75
|
+
items: { type: 'string' },
|
|
76
|
+
default: ['*'],
|
|
77
|
+
description: 'Entity ID patterns to version (glob patterns)'
|
|
78
|
+
},
|
|
79
|
+
excludeEntities: {
|
|
80
|
+
type: 'array',
|
|
81
|
+
items: { type: 'string' },
|
|
82
|
+
default: ['_version:*'],
|
|
83
|
+
description: 'Entity ID patterns to exclude (version metadata IDs start with _version:)'
|
|
84
|
+
},
|
|
85
|
+
types: {
|
|
86
|
+
type: 'array',
|
|
87
|
+
items: { type: 'string' },
|
|
88
|
+
default: [],
|
|
89
|
+
description: 'Entity types to version (empty = all)'
|
|
90
|
+
},
|
|
91
|
+
excludeTypes: {
|
|
92
|
+
type: 'array',
|
|
93
|
+
items: { type: 'string' },
|
|
94
|
+
default: [],
|
|
95
|
+
description: 'Entity types to exclude (versions use standard state type)'
|
|
96
|
+
},
|
|
97
|
+
keepRecent: {
|
|
98
|
+
type: 'number',
|
|
99
|
+
default: 10,
|
|
100
|
+
minimum: 1,
|
|
101
|
+
description: 'Keep N recent versions per entity'
|
|
102
|
+
},
|
|
103
|
+
keepTagged: {
|
|
104
|
+
type: 'boolean',
|
|
105
|
+
default: true,
|
|
106
|
+
description: 'Keep tagged versions during pruning'
|
|
107
|
+
},
|
|
108
|
+
tagPrefix: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
default: 'auto-',
|
|
111
|
+
description: 'Tag prefix for auto-generated versions'
|
|
112
|
+
},
|
|
113
|
+
autoPrune: {
|
|
114
|
+
type: 'boolean',
|
|
115
|
+
default: true,
|
|
116
|
+
description: 'Automatically prune old versions'
|
|
117
|
+
},
|
|
118
|
+
pruneInterval: {
|
|
119
|
+
type: 'number',
|
|
120
|
+
default: 3600000,
|
|
121
|
+
description: 'Prune interval in milliseconds (default: 1 hour)'
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
configDefaults: {
|
|
126
|
+
enabled: true,
|
|
127
|
+
onUpdate: true,
|
|
128
|
+
onAdd: false,
|
|
129
|
+
entities: ['*'],
|
|
130
|
+
excludeEntities: ['_version:*'],
|
|
131
|
+
types: [],
|
|
132
|
+
excludeTypes: [],
|
|
133
|
+
keepRecent: 10,
|
|
134
|
+
keepTagged: true,
|
|
135
|
+
tagPrefix: 'auto-',
|
|
136
|
+
autoPrune: true,
|
|
137
|
+
pruneInterval: 3600000
|
|
138
|
+
},
|
|
139
|
+
minBrainyVersion: '5.3.0',
|
|
140
|
+
keywords: ['versioning', 'history', 'audit', 'backup'],
|
|
141
|
+
documentation: 'https://docs.brainy.dev/versioning',
|
|
142
|
+
status: 'stable',
|
|
143
|
+
performance: {
|
|
144
|
+
memoryUsage: 'low',
|
|
145
|
+
cpuUsage: 'low',
|
|
146
|
+
networkUsage: 'none'
|
|
147
|
+
},
|
|
148
|
+
features: [
|
|
149
|
+
'auto-versioning',
|
|
150
|
+
'retention-policies',
|
|
151
|
+
'entity-filtering',
|
|
152
|
+
'event-hooks'
|
|
153
|
+
],
|
|
154
|
+
enhancedOperations: ['update', 'add'],
|
|
155
|
+
metrics: [
|
|
156
|
+
{
|
|
157
|
+
name: 'versions_created',
|
|
158
|
+
type: 'counter',
|
|
159
|
+
description: 'Total versions created by augmentation'
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'versions_pruned',
|
|
163
|
+
type: 'counter',
|
|
164
|
+
description: 'Total versions pruned by retention policies'
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
async onAttach(brain) {
|
|
170
|
+
// Store brain instance for entity fetching
|
|
171
|
+
this.brain = brain;
|
|
172
|
+
// Get VersioningAPI instance
|
|
173
|
+
this.versioningAPI = brain.versions;
|
|
174
|
+
// Start auto-prune timer if enabled
|
|
175
|
+
if (this.config.autoPrune && this.config.pruneInterval) {
|
|
176
|
+
this.startAutoPrune();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async onDetach() {
|
|
180
|
+
// Stop auto-prune timer
|
|
181
|
+
if (this.pruneTimer) {
|
|
182
|
+
clearInterval(this.pruneTimer);
|
|
183
|
+
this.pruneTimer = undefined;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Execute method (required by BaseAugmentation)
|
|
188
|
+
*/
|
|
189
|
+
async execute(operation, params, context) {
|
|
190
|
+
// Versioning augmentation only runs in 'after' mode
|
|
191
|
+
// Actual logic is in after() method
|
|
192
|
+
return context.originalResult;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* After operation hook - auto-save versions
|
|
196
|
+
*/
|
|
197
|
+
async after(operation, params, result) {
|
|
198
|
+
if (!this.config.enabled || !this.versioningAPI) {
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
// Check if we should version this operation
|
|
202
|
+
if (operation === 'update' && !this.config.onUpdate) {
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
if (operation === 'add' && !this.config.onAdd) {
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
// Extract entity ID from params
|
|
209
|
+
const entityId = this.extractEntityId(operation, params);
|
|
210
|
+
if (!entityId) {
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
// Check if entity should be versioned
|
|
214
|
+
if (!(await this.shouldVersionEntity(entityId))) {
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
// Prepare save options
|
|
219
|
+
let saveOptions = {
|
|
220
|
+
tag: `${this.config.tagPrefix}${Date.now()}`,
|
|
221
|
+
description: `Auto-saved after ${operation}`,
|
|
222
|
+
metadata: {
|
|
223
|
+
augmentation: 'versioning',
|
|
224
|
+
operation,
|
|
225
|
+
timestamp: Date.now()
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
// Call before-save hook
|
|
229
|
+
if (this.config.hooks?.beforeSave) {
|
|
230
|
+
const modifiedOptions = await this.config.hooks.beforeSave(entityId, saveOptions);
|
|
231
|
+
if (modifiedOptions === null) {
|
|
232
|
+
// Hook cancelled the save
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
saveOptions = modifiedOptions;
|
|
236
|
+
}
|
|
237
|
+
// Save version
|
|
238
|
+
const version = await this.versioningAPI.save(entityId, saveOptions);
|
|
239
|
+
this.versionCount++;
|
|
240
|
+
// Call after-save hook
|
|
241
|
+
if (this.config.hooks?.afterSave) {
|
|
242
|
+
await this.config.hooks.afterSave(entityId, version);
|
|
243
|
+
}
|
|
244
|
+
// Auto-prune if enabled
|
|
245
|
+
if (this.config.autoPrune) {
|
|
246
|
+
await this.pruneEntity(entityId);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
// Don't fail the operation if versioning fails
|
|
251
|
+
console.error(`Versioning augmentation error for ${entityId}:`, error);
|
|
252
|
+
}
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Extract entity ID from operation params
|
|
257
|
+
*/
|
|
258
|
+
extractEntityId(operation, params) {
|
|
259
|
+
if (operation === 'update') {
|
|
260
|
+
// update(id, data) or update({ id, ... })
|
|
261
|
+
if (typeof params[0] === 'string') {
|
|
262
|
+
return params[0];
|
|
263
|
+
}
|
|
264
|
+
if (params[0]?.id) {
|
|
265
|
+
return params[0].id;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (operation === 'add') {
|
|
269
|
+
// add(data) - ID might be in data or result
|
|
270
|
+
if (params[0]?.id) {
|
|
271
|
+
return params[0].id;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Check if entity should be versioned based on filters
|
|
278
|
+
*/
|
|
279
|
+
async shouldVersionEntity(entityId) {
|
|
280
|
+
// Check exclude patterns first (ID-based)
|
|
281
|
+
if (this.config.excludeEntities) {
|
|
282
|
+
for (const pattern of this.config.excludeEntities) {
|
|
283
|
+
if (this.matchPattern(entityId, pattern)) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// Check include patterns (ID-based)
|
|
289
|
+
if (this.config.entities && this.config.entities.length > 0) {
|
|
290
|
+
let matched = false;
|
|
291
|
+
for (const pattern of this.config.entities) {
|
|
292
|
+
if (this.matchPattern(entityId, pattern)) {
|
|
293
|
+
matched = true;
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (!matched)
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
// Check entity type filters (requires fetching entity)
|
|
301
|
+
if ((this.config.types && this.config.types.length > 0) ||
|
|
302
|
+
(this.config.excludeTypes && this.config.excludeTypes.length > 0)) {
|
|
303
|
+
try {
|
|
304
|
+
const entity = await this.brain?.getNounMetadata?.(entityId);
|
|
305
|
+
if (!entity)
|
|
306
|
+
return true; // If can't fetch, allow versioning
|
|
307
|
+
const entityType = entity.type;
|
|
308
|
+
// Check exclude types
|
|
309
|
+
if (this.config.excludeTypes && this.config.excludeTypes.includes(entityType)) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
// Check include types
|
|
313
|
+
if (this.config.types && this.config.types.length > 0) {
|
|
314
|
+
if (!this.config.types.includes(entityType)) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
// If can't fetch entity, allow versioning (fail open)
|
|
321
|
+
console.error(`Failed to fetch entity ${entityId} for type filtering:`, error);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Simple glob pattern matching
|
|
329
|
+
*/
|
|
330
|
+
matchPattern(value, pattern) {
|
|
331
|
+
if (pattern === '*')
|
|
332
|
+
return true;
|
|
333
|
+
if (!pattern.includes('*'))
|
|
334
|
+
return value === pattern;
|
|
335
|
+
// Convert glob to regex
|
|
336
|
+
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
|
|
337
|
+
return regex.test(value);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Prune old versions for an entity
|
|
341
|
+
*/
|
|
342
|
+
async pruneEntity(entityId) {
|
|
343
|
+
if (!this.versioningAPI)
|
|
344
|
+
return;
|
|
345
|
+
try {
|
|
346
|
+
// Call before-prune hook
|
|
347
|
+
if (this.config.hooks?.beforePrune) {
|
|
348
|
+
const shouldPrune = await this.config.hooks.beforePrune(entityId);
|
|
349
|
+
if (!shouldPrune)
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// Prune versions
|
|
353
|
+
const result = await this.versioningAPI.prune(entityId, {
|
|
354
|
+
keepRecent: this.config.keepRecent,
|
|
355
|
+
keepAfter: this.config.keepAfter,
|
|
356
|
+
keepTagged: this.config.keepTagged
|
|
357
|
+
});
|
|
358
|
+
// Call after-prune hook
|
|
359
|
+
if (result.deleted > 0 && this.config.hooks?.afterPrune) {
|
|
360
|
+
await this.config.hooks.afterPrune(entityId, result.deleted);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
console.error(`Failed to prune versions for ${entityId}:`, error);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Start auto-prune timer
|
|
369
|
+
*/
|
|
370
|
+
startAutoPrune() {
|
|
371
|
+
if (this.pruneTimer) {
|
|
372
|
+
clearInterval(this.pruneTimer);
|
|
373
|
+
}
|
|
374
|
+
this.pruneTimer = setInterval(async () => {
|
|
375
|
+
await this.pruneAllEntities();
|
|
376
|
+
}, this.config.pruneInterval);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Prune all versioned entities
|
|
380
|
+
*/
|
|
381
|
+
async pruneAllEntities() {
|
|
382
|
+
if (!this.versioningAPI)
|
|
383
|
+
return;
|
|
384
|
+
try {
|
|
385
|
+
// Get all versioned entities
|
|
386
|
+
const versionIndex = this.versioningAPI.manager.versionIndex;
|
|
387
|
+
const entities = await versionIndex.getVersionedEntities();
|
|
388
|
+
// Prune each entity
|
|
389
|
+
for (const entityId of entities) {
|
|
390
|
+
if (await this.shouldVersionEntity(entityId)) {
|
|
391
|
+
await this.pruneEntity(entityId);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
console.error('Auto-prune failed:', error);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Get augmentation statistics
|
|
401
|
+
*/
|
|
402
|
+
getStats() {
|
|
403
|
+
return {
|
|
404
|
+
enabled: this.config.enabled,
|
|
405
|
+
versionsCreated: this.versionCount,
|
|
406
|
+
entitiesPattern: this.config.entities || [],
|
|
407
|
+
excludePattern: this.config.excludeEntities || [],
|
|
408
|
+
retention: this.config.keepRecent || 10
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Factory function for easy augmentation creation
|
|
414
|
+
*/
|
|
415
|
+
export function createVersioningAugmentation(config = {}) {
|
|
416
|
+
return new VersioningAugmentation(config);
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=versioningAugmentation.js.map
|
package/dist/brainy.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { NaturalLanguageProcessor } from './neural/naturalLanguageProcessor.js';
|
|
|
10
10
|
import { ExtractedEntity } from './neural/entityExtractor.js';
|
|
11
11
|
import { TripleIntelligenceSystem } from './triple/TripleIntelligenceSystem.js';
|
|
12
12
|
import { VirtualFileSystem } from './vfs/VirtualFileSystem.js';
|
|
13
|
+
import { VersioningAPI } from './versioning/VersioningAPI.js';
|
|
13
14
|
import { Entity, Relation, Result, AddParams, UpdateParams, RelateParams, FindParams, SimilarParams, GetRelationsParams, AddManyParams, DeleteManyParams, RelateManyParams, BatchResult, BrainyConfig } from './types/brainy.types.js';
|
|
14
15
|
import { NounType, VerbType } from './types/graphTypes.js';
|
|
15
16
|
import { BrainyInterface } from './types/brainyInterface.js';
|
|
@@ -39,6 +40,7 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
|
|
|
39
40
|
private _nlp?;
|
|
40
41
|
private _extractor?;
|
|
41
42
|
private _tripleIntelligence?;
|
|
43
|
+
private _versions?;
|
|
42
44
|
private _vfs?;
|
|
43
45
|
private initialized;
|
|
44
46
|
private dimensions?;
|
|
@@ -956,6 +958,32 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
|
|
|
956
958
|
* Neural API - Advanced AI operations
|
|
957
959
|
*/
|
|
958
960
|
neural(): ImprovedNeuralAPI;
|
|
961
|
+
/**
|
|
962
|
+
* Versioning API - Entity version control (v5.3.0)
|
|
963
|
+
*
|
|
964
|
+
* Provides entity-level versioning with:
|
|
965
|
+
* - save() - Create version of entity
|
|
966
|
+
* - restore() - Restore entity to specific version
|
|
967
|
+
* - list() - List all versions of entity
|
|
968
|
+
* - compare() - Deep diff between versions
|
|
969
|
+
* - prune() - Remove old versions (retention policies)
|
|
970
|
+
*
|
|
971
|
+
* @example
|
|
972
|
+
* ```typescript
|
|
973
|
+
* // Save current state
|
|
974
|
+
* const version = await brain.versions.save('user-123', { tag: 'v1.0' })
|
|
975
|
+
*
|
|
976
|
+
* // List versions
|
|
977
|
+
* const versions = await brain.versions.list('user-123')
|
|
978
|
+
*
|
|
979
|
+
* // Restore to previous version
|
|
980
|
+
* await brain.versions.restore('user-123', 5)
|
|
981
|
+
*
|
|
982
|
+
* // Compare versions
|
|
983
|
+
* const diff = await brain.versions.compare('user-123', 2, 5)
|
|
984
|
+
* ```
|
|
985
|
+
*/
|
|
986
|
+
get versions(): VersioningAPI;
|
|
959
987
|
/**
|
|
960
988
|
* Natural Language Processing API
|
|
961
989
|
*/
|
package/dist/brainy.js
CHANGED
|
@@ -16,6 +16,7 @@ import { NaturalLanguageProcessor } from './neural/naturalLanguageProcessor.js';
|
|
|
16
16
|
import { NeuralEntityExtractor } from './neural/entityExtractor.js';
|
|
17
17
|
import { TripleIntelligenceSystem } from './triple/TripleIntelligenceSystem.js';
|
|
18
18
|
import { VirtualFileSystem } from './vfs/VirtualFileSystem.js';
|
|
19
|
+
import { VersioningAPI } from './versioning/VersioningAPI.js';
|
|
19
20
|
import { MetadataIndexManager } from './utils/metadataIndex.js';
|
|
20
21
|
import { GraphAdjacencyIndex } from './graph/graphAdjacencyIndex.js';
|
|
21
22
|
import { CommitBuilder } from './storage/cow/CommitObject.js';
|
|
@@ -2051,7 +2052,7 @@ export class Brainy {
|
|
|
2051
2052
|
// Build and persist commit (returns hash directly)
|
|
2052
2053
|
const commitHash = await builder.build();
|
|
2053
2054
|
// Update branch ref to point to new commit
|
|
2054
|
-
await refManager.setRef(
|
|
2055
|
+
await refManager.setRef(currentBranch, commitHash, {
|
|
2055
2056
|
author: options?.author || 'unknown',
|
|
2056
2057
|
message: options?.message || 'Snapshot commit'
|
|
2057
2058
|
});
|
|
@@ -2504,6 +2505,37 @@ export class Brainy {
|
|
|
2504
2505
|
}
|
|
2505
2506
|
return this._neural;
|
|
2506
2507
|
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Versioning API - Entity version control (v5.3.0)
|
|
2510
|
+
*
|
|
2511
|
+
* Provides entity-level versioning with:
|
|
2512
|
+
* - save() - Create version of entity
|
|
2513
|
+
* - restore() - Restore entity to specific version
|
|
2514
|
+
* - list() - List all versions of entity
|
|
2515
|
+
* - compare() - Deep diff between versions
|
|
2516
|
+
* - prune() - Remove old versions (retention policies)
|
|
2517
|
+
*
|
|
2518
|
+
* @example
|
|
2519
|
+
* ```typescript
|
|
2520
|
+
* // Save current state
|
|
2521
|
+
* const version = await brain.versions.save('user-123', { tag: 'v1.0' })
|
|
2522
|
+
*
|
|
2523
|
+
* // List versions
|
|
2524
|
+
* const versions = await brain.versions.list('user-123')
|
|
2525
|
+
*
|
|
2526
|
+
* // Restore to previous version
|
|
2527
|
+
* await brain.versions.restore('user-123', 5)
|
|
2528
|
+
*
|
|
2529
|
+
* // Compare versions
|
|
2530
|
+
* const diff = await brain.versions.compare('user-123', 2, 5)
|
|
2531
|
+
* ```
|
|
2532
|
+
*/
|
|
2533
|
+
get versions() {
|
|
2534
|
+
if (!this._versions) {
|
|
2535
|
+
this._versions = new VersioningAPI(this);
|
|
2536
|
+
}
|
|
2537
|
+
return this._versions;
|
|
2538
|
+
}
|
|
2507
2539
|
/**
|
|
2508
2540
|
* Natural Language Processing API
|
|
2509
2541
|
*/
|