attachment-store-file.mjs
91 lines 2.5 KB
Raw
sha256:baa800aedf841dbf32081aa7b2befa288ac33dfc7175ac55014c55c4d8c742f9 docs: move durable-auth freeze/evidence to local developmen… Human 10 days ago
1 /**
2 * Policy overlay persistence for derived attachments (Phase 2F-b-b).
3 *
4 * @see docs/ATTACHMENT-STORE-CONTRACT-2F-b.md §2
5 */
6
7 import fs from 'fs';
8 import path from 'path';
9 import { randomUUID } from 'crypto';
10
11 const STORE_FILENAME = 'hub_attachment_store.json';
12
13 /**
14 * @typedef {Object} AttachmentPolicy
15 * @property {boolean} agent_visible
16 * @property {'vault_lifetime'|'pinned'} retention
17 * @property {string} updated
18 */
19
20 /**
21 * @typedef {Object} VaultAttachmentPolicies
22 * @property {Record<string, AttachmentPolicy>} policies
23 */
24
25 /**
26 * @typedef {Object} AttachmentStoreFile
27 * @property {'knowtation.attachment_store/v0'} [schema]
28 * @property {Record<string, VaultAttachmentPolicies>} vaults
29 */
30
31 /**
32 * @param {string} dataDir
33 * @returns {string}
34 */
35 export function getAttachmentStorePath(dataDir) {
36 return path.join(dataDir, STORE_FILENAME);
37 }
38
39 /**
40 * @param {string} dataDir
41 * @returns {AttachmentStoreFile}
42 */
43 export function loadAttachmentStore(dataDir) {
44 const filePath = getAttachmentStorePath(dataDir);
45 if (!fs.existsSync(filePath)) {
46 return { schema: 'knowtation.attachment_store/v0', vaults: {} };
47 }
48 try {
49 const raw = fs.readFileSync(filePath, 'utf8');
50 const parsed = JSON.parse(raw);
51 if (!parsed || typeof parsed !== 'object' || !parsed.vaults || typeof parsed.vaults !== 'object') {
52 return { schema: 'knowtation.attachment_store/v0', vaults: {} };
53 }
54 return /** @type {AttachmentStoreFile} */ ({
55 schema: 'knowtation.attachment_store/v0',
56 vaults: parsed.vaults,
57 });
58 } catch {
59 return { schema: 'knowtation.attachment_store/v0', vaults: {} };
60 }
61 }
62
63 /**
64 * @param {string} dataDir
65 * @param {AttachmentStoreFile} store
66 */
67 export function saveAttachmentStore(dataDir, store) {
68 const filePath = getAttachmentStorePath(dataDir);
69 const dir = path.dirname(filePath);
70 if (!fs.existsSync(dir)) {
71 fs.mkdirSync(dir, { recursive: true });
72 }
73 const payload = { schema: 'knowtation.attachment_store/v0', vaults: store.vaults ?? {} };
74 const tmp = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
75 fs.writeFileSync(tmp, JSON.stringify(payload, null, 2), 'utf8');
76 fs.renameSync(tmp, filePath);
77 }
78
79 /**
80 * @param {string} dataDir
81 * @param {string} vaultId
82 * @returns {Record<string, AttachmentPolicy>}
83 */
84 export function getVaultAttachmentPolicies(dataDir, vaultId) {
85 const store = loadAttachmentStore(dataDir);
86 const vault = store.vaults?.[vaultId];
87 if (!vault || !vault.policies || typeof vault.policies !== 'object') {
88 return {};
89 }
90 return vault.policies;
91 }
File History 1 commit
sha256:baa800aedf841dbf32081aa7b2befa288ac33dfc7175ac55014c55c4d8c742f9 docs: move durable-auth freeze/evidence to local developmen… Human 10 days ago