scope-filter.mjs
67 lines 2.7 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * Filter note list/search results by per-user scope (projects + folders).
3 * Same behavior as applyScopeFilter in hub/server.mjs; used by gateway (hosted) and Node Hub.
4 *
5 * Each note: { path, project?, ... }
6 */
7
8 /**
9 * @param {Array<{ path?: string, project?: string | null }>} notes
10 * @param {{ projects?: string[], folders?: string[] } | null | undefined} scope
11 * @returns {Array<{ path?: string, project?: string | null }>}
12 */
13 export function applyScopeFilterToNotes(notes, scope) {
14 if (!scope || (!scope.projects?.length && !scope.folders?.length)) return notes;
15 const list = Array.isArray(notes) ? notes : [];
16 return list.filter((n) => {
17 if (scope.folders?.length) {
18 const p = n.path && typeof n.path === 'string' ? n.path : '';
19 const folder = p.includes('/') ? p.split('/').slice(0, -1).join('/') : '';
20 if (scope.folders.some((f) => folder === f || folder.startsWith(f + '/'))) return true;
21 }
22 if (scope.projects?.length && n.project && scope.projects.includes(n.project)) return true;
23 return false;
24 });
25 }
26
27 /**
28 * Filter proposals the same way as notes for hosted team scope (folder prefix + project slug).
29 * Full proposal objects from GET /proposals/:id include `path`; `project` may appear in frontmatter.
30 *
31 * @param {Array<{ path?: string, project?: string | null, frontmatter?: string | object }>} proposals
32 * @param {{ projects?: string[], folders?: string[] } | null | undefined} scope
33 * @returns {typeof proposals}
34 */
35 export function applyScopeFilterToProposals(proposals, scope) {
36 if (!scope || (!scope.projects?.length && !scope.folders?.length)) return proposals;
37 const list = Array.isArray(proposals) ? proposals : [];
38 return list.filter((p) => {
39 const pathStr = p.path && typeof p.path === 'string' ? p.path : '';
40 if (scope.folders?.length) {
41 const folder = pathStr.includes('/') ? pathStr.split('/').slice(0, -1).join('/') : '';
42 if (scope.folders.some((f) => folder === f || folder.startsWith(f + '/'))) return true;
43 }
44 if (scope.projects?.length) {
45 let proj = p.project && typeof p.project === 'string' ? p.project : null;
46 if (!proj && pathStr.startsWith('projects/')) {
47 const rest = pathStr.slice('projects/'.length);
48 proj = rest.split('/')[0] || null;
49 }
50 if (!proj && p.frontmatter) {
51 let fm = p.frontmatter;
52 if (typeof fm === 'string' && fm.trim()) {
53 try {
54 fm = JSON.parse(fm);
55 } catch {
56 fm = null;
57 }
58 }
59 if (fm && typeof fm === 'object' && !Array.isArray(fm) && fm.project) {
60 proj = String(fm.project);
61 }
62 }
63 if (proj && scope.projects.includes(proj)) return true;
64 }
65 return false;
66 });
67 }
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago