loop-pass-audit-blob-store.mjs
75 lines 2.2 KB
Raw
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor ⚠ breaking 10 days ago
1 /**
2 * Hosted bridge: persist loop pass audit JSON in Netlify Blobs (Phase 2G hosted parity).
3 */
4
5 import fs from 'fs';
6 import path from 'path';
7 import { LOOP_PASS_AUDIT_FILE, LOOP_PASS_AUDIT_POLICY_FILE } from '../../lib/task/loop-pass-audit.mjs';
8
9 /** @typedef {{ get: (key: string, opts?: { type?: string }) => Promise<string|ArrayBuffer|null>, set: (key: string, value: string) => Promise<void> }} BlobStore */
10
11 export const LOOP_PASS_AUDIT_BLOB_FILES = [LOOP_PASS_AUDIT_FILE, LOOP_PASS_AUDIT_POLICY_FILE];
12
13 /**
14 * @param {string} filename
15 * @returns {string}
16 */
17 export function loopPassAuditBlobKey(filename) {
18 return `loop_pass_audit/${filename}`;
19 }
20
21 /**
22 * @param {BlobStore|null|undefined} blobStore
23 * @param {string} dataDir
24 */
25 export async function hydrateLoopPassAuditStoresFromBlob(blobStore, dataDir) {
26 if (!blobStore || typeof blobStore.get !== 'function') return;
27 fs.mkdirSync(dataDir, { recursive: true });
28 for (const filename of LOOP_PASS_AUDIT_BLOB_FILES) {
29 const fp = path.join(dataDir, filename);
30 try {
31 const raw = await blobStore.get(loopPassAuditBlobKey(filename), { type: 'text' });
32 if (typeof raw === 'string' && raw.trim()) {
33 fs.writeFileSync(fp, raw, 'utf8');
34 }
35 } catch {
36 /* keep existing file or empty */
37 }
38 }
39 }
40
41 /**
42 * @param {BlobStore|null|undefined} blobStore
43 * @param {string} dataDir
44 */
45 export async function persistLoopPassAuditStoresToBlob(blobStore, dataDir) {
46 if (!blobStore || typeof blobStore.set !== 'function') return;
47 for (const filename of LOOP_PASS_AUDIT_BLOB_FILES) {
48 const fp = path.join(dataDir, filename);
49 if (!fs.existsSync(fp)) continue;
50 try {
51 const raw = fs.readFileSync(fp, 'utf8');
52 if (raw.trim()) {
53 await blobStore.set(loopPassAuditBlobKey(filename), raw);
54 }
55 } catch {
56 /* non-fatal */
57 }
58 }
59 }
60
61 /**
62 * @template T
63 * @param {{
64 * blobStore: BlobStore|null|undefined,
65 * dataDir: string,
66 * run: () => T | Promise<T>,
67 * }} opts
68 * @returns {Promise<T>}
69 */
70 export async function withLoopPassAuditBlobSync(opts) {
71 await hydrateLoopPassAuditStoresFromBlob(opts.blobStore, opts.dataDir);
72 const result = await opts.run();
73 await persistLoopPassAuditStoresToBlob(opts.blobStore, opts.dataDir);
74 return result;
75 }
File History 1 commit
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor 10 days ago