@pcircle/footprint 1.0.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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/SKILL.md +355 -0
  4. package/dist/index.d.ts +19 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +690 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/lib/crypto/decrypt.d.ts +11 -0
  9. package/dist/lib/crypto/decrypt.d.ts.map +1 -0
  10. package/dist/lib/crypto/decrypt.js +30 -0
  11. package/dist/lib/crypto/decrypt.js.map +1 -0
  12. package/dist/lib/crypto/encrypt.d.ts +13 -0
  13. package/dist/lib/crypto/encrypt.d.ts.map +1 -0
  14. package/dist/lib/crypto/encrypt.js +24 -0
  15. package/dist/lib/crypto/encrypt.js.map +1 -0
  16. package/dist/lib/crypto/index.d.ts +6 -0
  17. package/dist/lib/crypto/index.d.ts.map +1 -0
  18. package/dist/lib/crypto/index.js +5 -0
  19. package/dist/lib/crypto/index.js.map +1 -0
  20. package/dist/lib/crypto/key-derivation.d.ts +30 -0
  21. package/dist/lib/crypto/key-derivation.d.ts.map +1 -0
  22. package/dist/lib/crypto/key-derivation.js +63 -0
  23. package/dist/lib/crypto/key-derivation.js.map +1 -0
  24. package/dist/lib/crypto/types.d.ts +22 -0
  25. package/dist/lib/crypto/types.d.ts.map +1 -0
  26. package/dist/lib/crypto/types.js +10 -0
  27. package/dist/lib/crypto/types.js.map +1 -0
  28. package/dist/lib/storage/database.d.ts +116 -0
  29. package/dist/lib/storage/database.d.ts.map +1 -0
  30. package/dist/lib/storage/database.js +390 -0
  31. package/dist/lib/storage/database.js.map +1 -0
  32. package/dist/lib/storage/export.d.ts +26 -0
  33. package/dist/lib/storage/export.d.ts.map +1 -0
  34. package/dist/lib/storage/export.js +113 -0
  35. package/dist/lib/storage/export.js.map +1 -0
  36. package/dist/lib/storage/git.d.ts +16 -0
  37. package/dist/lib/storage/git.d.ts.map +1 -0
  38. package/dist/lib/storage/git.js +55 -0
  39. package/dist/lib/storage/git.js.map +1 -0
  40. package/dist/lib/storage/index.d.ts +6 -0
  41. package/dist/lib/storage/index.d.ts.map +1 -0
  42. package/dist/lib/storage/index.js +5 -0
  43. package/dist/lib/storage/index.js.map +1 -0
  44. package/dist/lib/storage/schema.d.ts +17 -0
  45. package/dist/lib/storage/schema.d.ts.map +1 -0
  46. package/dist/lib/storage/schema.js +103 -0
  47. package/dist/lib/storage/schema.js.map +1 -0
  48. package/dist/lib/storage/types.d.ts +26 -0
  49. package/dist/lib/storage/types.d.ts.map +1 -0
  50. package/dist/lib/storage/types.js +2 -0
  51. package/dist/lib/storage/types.js.map +1 -0
  52. package/dist/test-helpers.d.ts +33 -0
  53. package/dist/test-helpers.d.ts.map +1 -0
  54. package/dist/test-helpers.js +108 -0
  55. package/dist/test-helpers.js.map +1 -0
  56. package/dist/types.d.ts +29 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +2 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/ui/dashboard.html +965 -0
  61. package/dist/ui/detail.html +348 -0
  62. package/dist/ui/export.html +409 -0
  63. package/dist/ui/register.d.ts +7 -0
  64. package/dist/ui/register.d.ts.map +1 -0
  65. package/dist/ui/register.js +154 -0
  66. package/dist/ui/register.js.map +1 -0
  67. package/dist/ui-tmp/ui/export.html +409 -0
  68. package/package.json +78 -0
@@ -0,0 +1,390 @@
1
+ import Database from 'better-sqlite3';
2
+ import { createSchema } from './schema.js';
3
+ /**
4
+ * Evidence database with CRUD operations
5
+ * Manages encrypted evidence storage with SQLite backend
6
+ */
7
+ export class EvidenceDatabase {
8
+ db;
9
+ /**
10
+ * Creates or opens an evidence database
11
+ * @param dbPath - Path to SQLite database file
12
+ */
13
+ constructor(dbPath) {
14
+ this.db = new Database(dbPath);
15
+ createSchema(this.db);
16
+ }
17
+ /**
18
+ * Creates a new evidence record
19
+ * @param evidence - Evidence data without id, createdAt, updatedAt
20
+ * @returns UUID of created evidence
21
+ */
22
+ create(evidence) {
23
+ const id = crypto.randomUUID();
24
+ const now = new Date().toISOString();
25
+ try {
26
+ const stmt = this.db.prepare(`
27
+ INSERT INTO evidences (
28
+ id, timestamp, conversationId, llmProvider,
29
+ encryptedContent, nonce, contentHash, messageCount,
30
+ gitCommitHash, gitTimestamp, tags, createdAt, updatedAt
31
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
32
+ `);
33
+ stmt.run(id, evidence.timestamp, evidence.conversationId, evidence.llmProvider, Buffer.from(evidence.encryptedContent), Buffer.from(evidence.nonce), evidence.contentHash, evidence.messageCount, evidence.gitCommitHash, evidence.gitTimestamp, evidence.tags, now, now);
34
+ return id;
35
+ }
36
+ catch (error) {
37
+ throw new Error(`Failed to create evidence: ${error instanceof Error ? error.message : String(error)}`);
38
+ }
39
+ }
40
+ /**
41
+ * Finds evidence by ID
42
+ * @param id - Evidence UUID
43
+ * @returns Evidence or null if not found
44
+ */
45
+ findById(id) {
46
+ try {
47
+ const stmt = this.db.prepare(`
48
+ SELECT * FROM evidences WHERE id = ?
49
+ `);
50
+ const row = stmt.get(id);
51
+ if (!row) {
52
+ return null;
53
+ }
54
+ return this.rowToEvidence(row);
55
+ }
56
+ catch (error) {
57
+ // Don't swallow database errors - re-throw with context
58
+ throw new Error(`Failed to find evidence by ID: ${error instanceof Error ? error.message : String(error)}`);
59
+ }
60
+ }
61
+ /**
62
+ * Finds all evidences for a conversation
63
+ * @param conversationId - Conversation identifier
64
+ * @returns Array of evidences (empty if none found)
65
+ */
66
+ findByConversationId(conversationId) {
67
+ try {
68
+ const stmt = this.db.prepare(`
69
+ SELECT * FROM evidences
70
+ WHERE conversationId = ?
71
+ ORDER BY timestamp ASC
72
+ `);
73
+ const rows = stmt.all(conversationId);
74
+ return rows.map((row) => this.rowToEvidence(row));
75
+ }
76
+ catch (error) {
77
+ throw new Error(`Failed to find evidences by conversationId: ${error instanceof Error ? error.message : String(error)}`);
78
+ }
79
+ }
80
+ /**
81
+ * Lists evidences with pagination
82
+ * @param options - Pagination options (limit, offset)
83
+ * @returns Array of evidences
84
+ */
85
+ list(options) {
86
+ try {
87
+ const limit = options?.limit;
88
+ const offset = options?.offset ?? 0;
89
+ let query = 'SELECT * FROM evidences ORDER BY timestamp DESC';
90
+ const params = [];
91
+ if (limit !== undefined) {
92
+ query += ' LIMIT ?';
93
+ params.push(limit);
94
+ if (offset > 0) {
95
+ query += ' OFFSET ?';
96
+ params.push(offset);
97
+ }
98
+ }
99
+ else if (offset > 0) {
100
+ query += ' LIMIT -1 OFFSET ?';
101
+ params.push(offset);
102
+ }
103
+ const stmt = this.db.prepare(query);
104
+ const rows = stmt.all(...params);
105
+ return rows.map((row) => this.rowToEvidence(row));
106
+ }
107
+ catch (error) {
108
+ throw new Error(`Failed to list evidences: ${error instanceof Error ? error.message : String(error)}`);
109
+ }
110
+ }
111
+ /**
112
+ * Updates git commit information for an evidence
113
+ * @param id - Evidence UUID
114
+ * @param gitCommitHash - Git commit hash
115
+ * @param gitTimestamp - Git commit timestamp (ISO 8601)
116
+ */
117
+ updateGitInfo(id, gitCommitHash, gitTimestamp) {
118
+ try {
119
+ const stmt = this.db.prepare(`
120
+ UPDATE evidences
121
+ SET gitCommitHash = ?,
122
+ gitTimestamp = ?,
123
+ updatedAt = ?
124
+ WHERE id = ?
125
+ `);
126
+ const result = stmt.run(gitCommitHash, gitTimestamp, new Date().toISOString(), id);
127
+ if (result.changes === 0) {
128
+ throw new Error(`Evidence with id ${id} not found`);
129
+ }
130
+ }
131
+ catch (error) {
132
+ throw new Error(`Failed to update git info: ${error instanceof Error ? error.message : String(error)}`);
133
+ }
134
+ }
135
+ /**
136
+ * Adds tags to an evidence (appends to existing tags)
137
+ * @param id - Evidence UUID
138
+ * @param tags - Array of tags to add
139
+ */
140
+ addTags(id, tags) {
141
+ try {
142
+ // First, get existing tags
143
+ const evidence = this.findById(id);
144
+ if (!evidence) {
145
+ throw new Error(`Evidence with id ${id} not found`);
146
+ }
147
+ // Parse existing tags (comma-separated) or create empty array
148
+ const existingTags = evidence.tags
149
+ ? evidence.tags.split(',').map(t => t.trim()).filter(t => t)
150
+ : [];
151
+ // Merge tags (deduplicate)
152
+ const mergedTags = [...new Set([...existingTags, ...tags.map(t => t.trim())])];
153
+ // Update database with comma-separated format
154
+ const stmt = this.db.prepare(`
155
+ UPDATE evidences
156
+ SET tags = ?,
157
+ updatedAt = ?
158
+ WHERE id = ?
159
+ `);
160
+ stmt.run(mergedTags.join(','), new Date().toISOString(), id);
161
+ }
162
+ catch (error) {
163
+ throw new Error(`Failed to add tags: ${error instanceof Error ? error.message : String(error)}`);
164
+ }
165
+ }
166
+ /**
167
+ * Search and filter evidences by various criteria
168
+ * @param options - Search and filter options
169
+ * @returns Array of matching evidences
170
+ */
171
+ search(options) {
172
+ try {
173
+ const { query, tags, dateFrom, dateTo, limit, offset = 0 } = options;
174
+ // Build WHERE conditions
175
+ const conditions = [];
176
+ const params = [];
177
+ // Text search in conversationId and tags
178
+ if (query && query.trim()) {
179
+ conditions.push(`(conversationId LIKE ? OR tags LIKE ?)`);
180
+ const searchPattern = `%${query.trim()}%`;
181
+ params.push(searchPattern, searchPattern);
182
+ }
183
+ // Tag filtering (AND logic - all specified tags must be present)
184
+ // Tags are stored as comma-separated strings: "tag1,tag2,tag3"
185
+ if (tags && tags.length > 0) {
186
+ for (const tag of tags) {
187
+ // Match tag at start, middle, or end of comma-separated list
188
+ conditions.push(`(tags LIKE ? OR tags LIKE ? OR tags LIKE ? OR tags = ?)`);
189
+ const trimmedTag = tag.trim();
190
+ params.push(`${trimmedTag},%`, // tag at start: "tag1,..."
191
+ `%,${trimmedTag},%`, // tag in middle: "...,tag1,..."
192
+ `%,${trimmedTag}`, // tag at end: "...,tag1"
193
+ trimmedTag // exact match (single tag)
194
+ );
195
+ }
196
+ }
197
+ // Date range filtering
198
+ if (dateFrom) {
199
+ conditions.push(`timestamp >= ?`);
200
+ params.push(dateFrom);
201
+ }
202
+ if (dateTo) {
203
+ conditions.push(`timestamp <= ?`);
204
+ params.push(dateTo);
205
+ }
206
+ // Build final query
207
+ let sql = 'SELECT * FROM evidences';
208
+ if (conditions.length > 0) {
209
+ sql += ' WHERE ' + conditions.join(' AND ');
210
+ }
211
+ sql += ' ORDER BY timestamp DESC';
212
+ // Add pagination
213
+ if (limit !== undefined) {
214
+ sql += ' LIMIT ?';
215
+ params.push(limit);
216
+ if (offset > 0) {
217
+ sql += ' OFFSET ?';
218
+ params.push(offset);
219
+ }
220
+ }
221
+ else if (offset > 0) {
222
+ sql += ' LIMIT -1 OFFSET ?';
223
+ params.push(offset);
224
+ }
225
+ const stmt = this.db.prepare(sql);
226
+ const rows = stmt.all(...params);
227
+ return rows.map((row) => this.rowToEvidence(row));
228
+ }
229
+ catch (error) {
230
+ throw new Error(`Failed to search evidences: ${error instanceof Error ? error.message : String(error)}`);
231
+ }
232
+ }
233
+ /**
234
+ * Deletes evidence by ID
235
+ * @param id - Evidence UUID
236
+ * @returns true if deleted, false if not found
237
+ */
238
+ delete(id) {
239
+ try {
240
+ const stmt = this.db.prepare(`DELETE FROM evidences WHERE id = ?`);
241
+ const result = stmt.run(id);
242
+ return result.changes > 0;
243
+ }
244
+ catch (error) {
245
+ throw new Error(`Failed to delete evidence: ${error instanceof Error ? error.message : String(error)}`);
246
+ }
247
+ }
248
+ /**
249
+ * Deletes multiple evidences by IDs
250
+ * @param ids - Array of evidence UUIDs
251
+ * @returns Number of evidences deleted
252
+ */
253
+ deleteMany(ids) {
254
+ if (ids.length === 0)
255
+ return 0;
256
+ try {
257
+ const placeholders = ids.map(() => '?').join(',');
258
+ const stmt = this.db.prepare(`DELETE FROM evidences WHERE id IN (${placeholders})`);
259
+ const result = stmt.run(...ids);
260
+ return result.changes;
261
+ }
262
+ catch (error) {
263
+ throw new Error(`Failed to delete evidences: ${error instanceof Error ? error.message : String(error)}`);
264
+ }
265
+ }
266
+ /**
267
+ * Updates tags for an evidence (replaces existing tags)
268
+ * @param id - Evidence UUID
269
+ * @param tags - New tags (comma-separated string or null)
270
+ * @returns true if updated, false if not found
271
+ */
272
+ updateTags(id, tags) {
273
+ try {
274
+ const stmt = this.db.prepare(`
275
+ UPDATE evidences
276
+ SET tags = ?,
277
+ updatedAt = ?
278
+ WHERE id = ?
279
+ `);
280
+ const result = stmt.run(tags, new Date().toISOString(), id);
281
+ return result.changes > 0;
282
+ }
283
+ catch (error) {
284
+ throw new Error(`Failed to update tags: ${error instanceof Error ? error.message : String(error)}`);
285
+ }
286
+ }
287
+ /**
288
+ * Renames a tag across all evidences
289
+ * @param oldTag - Tag to rename
290
+ * @param newTag - New tag name
291
+ * @returns Number of evidences updated
292
+ */
293
+ renameTag(oldTag, newTag) {
294
+ try {
295
+ // Get all evidences with this tag
296
+ const evidences = this.search({ tags: [oldTag] });
297
+ let updatedCount = 0;
298
+ for (const evidence of evidences) {
299
+ if (!evidence.tags)
300
+ continue;
301
+ const tags = evidence.tags.split(',').map(t => t.trim());
302
+ const newTags = tags.map(t => t === oldTag ? newTag : t);
303
+ if (this.updateTags(evidence.id, newTags.join(','))) {
304
+ updatedCount++;
305
+ }
306
+ }
307
+ return updatedCount;
308
+ }
309
+ catch (error) {
310
+ throw new Error(`Failed to rename tag: ${error instanceof Error ? error.message : String(error)}`);
311
+ }
312
+ }
313
+ /**
314
+ * Removes a tag from all evidences
315
+ * @param tag - Tag to remove
316
+ * @returns Number of evidences updated
317
+ */
318
+ removeTag(tag) {
319
+ try {
320
+ // Get all evidences with this tag
321
+ const evidences = this.search({ tags: [tag] });
322
+ let updatedCount = 0;
323
+ for (const evidence of evidences) {
324
+ if (!evidence.tags)
325
+ continue;
326
+ const tags = evidence.tags.split(',').map(t => t.trim()).filter(t => t !== tag);
327
+ const newTags = tags.length > 0 ? tags.join(',') : null;
328
+ if (this.updateTags(evidence.id, newTags)) {
329
+ updatedCount++;
330
+ }
331
+ }
332
+ return updatedCount;
333
+ }
334
+ catch (error) {
335
+ throw new Error(`Failed to remove tag: ${error instanceof Error ? error.message : String(error)}`);
336
+ }
337
+ }
338
+ /**
339
+ * Gets all unique tags with their counts
340
+ * @returns Map of tag to count
341
+ */
342
+ getTagCounts() {
343
+ try {
344
+ const stmt = this.db.prepare(`SELECT tags FROM evidences WHERE tags IS NOT NULL AND tags != ''`);
345
+ const rows = stmt.all();
346
+ const tagCounts = new Map();
347
+ for (const row of rows) {
348
+ const tags = row.tags.split(',').map(t => t.trim()).filter(t => t);
349
+ for (const tag of tags) {
350
+ tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
351
+ }
352
+ }
353
+ return tagCounts;
354
+ }
355
+ catch (error) {
356
+ throw new Error(`Failed to get tag counts: ${error instanceof Error ? error.message : String(error)}`);
357
+ }
358
+ }
359
+ /**
360
+ * Closes the database connection
361
+ * Should be called when done with the database
362
+ */
363
+ close() {
364
+ this.db.close();
365
+ }
366
+ /**
367
+ * Converts database row to Evidence object
368
+ * Handles BLOB to Uint8Array conversion
369
+ * @param row - Raw database row
370
+ * @returns Evidence object
371
+ */
372
+ rowToEvidence(row) {
373
+ return {
374
+ id: row.id,
375
+ timestamp: row.timestamp,
376
+ conversationId: row.conversationId,
377
+ llmProvider: row.llmProvider,
378
+ encryptedContent: new Uint8Array(row.encryptedContent),
379
+ nonce: new Uint8Array(row.nonce),
380
+ contentHash: row.contentHash,
381
+ messageCount: row.messageCount,
382
+ gitCommitHash: row.gitCommitHash,
383
+ gitTimestamp: row.gitTimestamp,
384
+ tags: row.tags,
385
+ createdAt: row.createdAt,
386
+ updatedAt: row.updatedAt
387
+ };
388
+ }
389
+ }
390
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../../src/lib/storage/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { EvidenceDatabase } from './database.js';
2
+ export interface ExportOptions {
3
+ evidenceIds?: string[];
4
+ includeGitInfo?: boolean;
5
+ password?: string;
6
+ }
7
+ export interface ExportResult {
8
+ filename: string;
9
+ zipData: Uint8Array;
10
+ checksum: string;
11
+ evidenceCount: number;
12
+ }
13
+ /**
14
+ * Export evidences to a ZIP archive with encrypted data and metadata.
15
+ *
16
+ * ⚠️ **Memory Warning**: Entire ZIP is generated in-memory. For large exports
17
+ * (>1000 evidences or >100MB encrypted data), consider exporting in batches
18
+ * to avoid memory exhaustion.
19
+ *
20
+ * @param db - EvidenceDatabase instance
21
+ * @param options - Export options
22
+ * @returns Export result with ZIP data and metadata
23
+ * @throws Error if database operations fail, IDs not found, or ZIP generation fails
24
+ */
25
+ export declare function exportEvidences(db: EvidenceDatabase, options?: ExportOptions): Promise<ExportResult>;
26
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/export.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAYD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,gBAAgB,EACpB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAiHvB"}
@@ -0,0 +1,113 @@
1
+ import JSZip from 'jszip';
2
+ import { createHash } from 'node:crypto';
3
+ // Export format version constant
4
+ const EXPORT_FORMAT_VERSION = '1.0.0';
5
+ /**
6
+ * Export evidences to a ZIP archive with encrypted data and metadata.
7
+ *
8
+ * ⚠️ **Memory Warning**: Entire ZIP is generated in-memory. For large exports
9
+ * (>1000 evidences or >100MB encrypted data), consider exporting in batches
10
+ * to avoid memory exhaustion.
11
+ *
12
+ * @param db - EvidenceDatabase instance
13
+ * @param options - Export options
14
+ * @returns Export result with ZIP data and metadata
15
+ * @throws Error if database operations fail, IDs not found, or ZIP generation fails
16
+ */
17
+ export async function exportEvidences(db, options = {}) {
18
+ try {
19
+ const { evidenceIds, includeGitInfo = false } = options;
20
+ // Get evidences to export - validate IDs if specified
21
+ let evidences;
22
+ if (evidenceIds) {
23
+ // Validate all IDs exist first
24
+ const notFound = evidenceIds.filter(id => !db.findById(id));
25
+ if (notFound.length > 0) {
26
+ throw new Error(`Evidence IDs not found: ${notFound.join(', ')}`);
27
+ }
28
+ evidences = evidenceIds.map(id => db.findById(id));
29
+ }
30
+ else {
31
+ evidences = db.list();
32
+ }
33
+ // Create ZIP archive
34
+ const zip = new JSZip();
35
+ // Add manifest.json
36
+ const manifest = {
37
+ version: EXPORT_FORMAT_VERSION,
38
+ exportDate: new Date().toISOString(),
39
+ evidenceCount: evidences.length,
40
+ includeGitInfo,
41
+ };
42
+ zip.file('manifest.json', JSON.stringify(manifest, null, 2));
43
+ // Add each evidence
44
+ const checksumEntries = [];
45
+ for (const evidence of evidences) {
46
+ const evidenceFolder = `evidences/${evidence.id}`;
47
+ // Add encrypted-data
48
+ zip.file(`${evidenceFolder}/encrypted-data`, evidence.encryptedContent);
49
+ // Calculate checksum for encrypted data
50
+ const dataChecksum = createHash('sha256')
51
+ .update(evidence.encryptedContent)
52
+ .digest('hex');
53
+ checksumEntries.push(`${dataChecksum} ${evidenceFolder}/encrypted-data`);
54
+ // Add metadata.json
55
+ const metadata = {
56
+ id: evidence.id,
57
+ timestamp: evidence.timestamp,
58
+ conversationId: evidence.conversationId,
59
+ llmProvider: evidence.llmProvider,
60
+ contentHash: evidence.contentHash,
61
+ messageCount: evidence.messageCount,
62
+ tags: evidence.tags,
63
+ nonce: Array.from(evidence.nonce), // Convert Uint8Array to array for JSON
64
+ };
65
+ const metadataJson = JSON.stringify(metadata, null, 2);
66
+ zip.file(`${evidenceFolder}/metadata.json`, metadataJson);
67
+ const metadataChecksum = createHash('sha256')
68
+ .update(metadataJson)
69
+ .digest('hex');
70
+ checksumEntries.push(`${metadataChecksum} ${evidenceFolder}/metadata.json`);
71
+ // Add git-info.json if requested and available
72
+ if (includeGitInfo && evidence.gitCommitHash && evidence.gitTimestamp) {
73
+ const gitInfo = {
74
+ gitCommitHash: evidence.gitCommitHash,
75
+ gitTimestamp: evidence.gitTimestamp,
76
+ };
77
+ const gitInfoJson = JSON.stringify(gitInfo, null, 2);
78
+ zip.file(`${evidenceFolder}/git-info.json`, gitInfoJson);
79
+ const gitChecksum = createHash('sha256').update(gitInfoJson).digest('hex');
80
+ checksumEntries.push(`${gitChecksum} ${evidenceFolder}/git-info.json`);
81
+ }
82
+ }
83
+ // Add checksum.txt
84
+ const checksumContent = [
85
+ 'SHA-256 Checksums',
86
+ '=================',
87
+ '',
88
+ ...checksumEntries,
89
+ ].join('\n');
90
+ zip.file('checksum.txt', checksumContent);
91
+ // Generate ZIP data
92
+ const zipData = await zip.generateAsync({
93
+ type: 'uint8array',
94
+ compression: 'DEFLATE',
95
+ compressionOptions: { level: 9 },
96
+ });
97
+ // Calculate ZIP checksum
98
+ const zipChecksum = createHash('sha256').update(zipData).digest('hex');
99
+ // Generate filename
100
+ const timestamp = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
101
+ const filename = `evidence-export-${timestamp}.zip`;
102
+ return {
103
+ filename,
104
+ zipData,
105
+ checksum: zipChecksum,
106
+ evidenceCount: evidences.length,
107
+ };
108
+ }
109
+ catch (error) {
110
+ throw new Error(`Failed to export evidences: ${error instanceof Error ? error.message : 'Unknown error'}`);
111
+ }
112
+ }
113
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/lib/storage/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Git commit information
3
+ */
4
+ export interface GitInfo {
5
+ commitHash: string;
6
+ timestamp: string;
7
+ message?: string;
8
+ author?: string;
9
+ }
10
+ /**
11
+ * Get current Git commit information
12
+ * @param dir - Directory path (defaults to process.cwd())
13
+ * @returns GitInfo or null if not a git repository
14
+ */
15
+ export declare function getCurrentCommit(dir?: string): Promise<GitInfo | null>;
16
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/git.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA+BzB"}
@@ -0,0 +1,55 @@
1
+ import git from 'isomorphic-git';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ /**
5
+ * Find git root directory by walking up the directory tree
6
+ * @param startDir - Starting directory
7
+ * @returns Git root directory or null if not found
8
+ */
9
+ async function findGitRoot(startDir) {
10
+ let currentDir = path.resolve(startDir);
11
+ const root = path.parse(currentDir).root;
12
+ while (currentDir !== root) {
13
+ const gitDir = path.join(currentDir, '.git');
14
+ if (fs.existsSync(gitDir)) {
15
+ return currentDir;
16
+ }
17
+ currentDir = path.dirname(currentDir);
18
+ }
19
+ return null;
20
+ }
21
+ /**
22
+ * Get current Git commit information
23
+ * @param dir - Directory path (defaults to process.cwd())
24
+ * @returns GitInfo or null if not a git repository
25
+ */
26
+ export async function getCurrentCommit(dir = process.cwd()) {
27
+ try {
28
+ // Find git root directory
29
+ const gitRoot = await findGitRoot(dir);
30
+ if (!gitRoot) {
31
+ return null;
32
+ }
33
+ // Get current commit SHA
34
+ const commits = await git.log({
35
+ fs,
36
+ dir: gitRoot,
37
+ depth: 1,
38
+ });
39
+ if (commits.length === 0) {
40
+ return null;
41
+ }
42
+ const commit = commits[0];
43
+ return {
44
+ commitHash: commit.oid,
45
+ timestamp: new Date(commit.commit.committer.timestamp * 1000).toISOString(),
46
+ message: commit.commit.message,
47
+ author: commit.commit.author.name,
48
+ };
49
+ }
50
+ catch (error) {
51
+ // Not a git repository or other git error
52
+ return null;
53
+ }
54
+ }
55
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/lib/storage/git.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,gBAAgB,CAAC;AACjC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAYxB;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,QAAgB;IACzC,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IAEzC,OAAO,UAAU,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,IAAI,CAAC;QACH,0BAA0B;QAC1B,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC;YAC5B,EAAE;YACF,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE1B,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,GAAG;YACtB,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;YAC3E,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;YAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;SAClC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0CAA0C;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { createSchema, verifySchema } from './schema.js';
2
+ export { EvidenceDatabase } from './database.js';
3
+ export type { Evidence, Metadata } from './types.js';
4
+ export { getCurrentCommit, type GitInfo } from './git.js';
5
+ export { exportEvidences, type ExportOptions, type ExportResult } from './export.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { createSchema, verifySchema } from './schema.js';
2
+ export { EvidenceDatabase } from './database.js';
3
+ export { getCurrentCommit } from './git.js';
4
+ export { exportEvidences } from './export.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAgB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAyC,MAAM,aAAa,CAAC"}