write-helpers.mjs
130 lines 3.9 KB
Raw
sha256:c2dbf04d56308f3bbf2d06e6d2eb022b8948b1e827195fe525a44e5e18d5f9c0 feat(auth): Phase B Connect cloud agent (RFC 8628) + Hermes… Human minor ⚠ breaking 11 days ago
1 /**
2 * Shared helpers for media-write seven-tier tests.
3 */
4 import fs from 'node:fs';
5 import path from 'node:path';
6
7 import {
8 precheckApprovedMediaProposal,
9 reconcileApprovedMediaProposal,
10 deriveLinkAttachmentId,
11 } from '../../../lib/attachments/attachment-write.mjs';
12 import {
13 saveMediaConnectorPolicy,
14 loadMediaConnectorPolicy,
15 } from '../../../lib/attachments/media-connector-policy.mjs';
16 import {
17 handleMediaImportConsentGrantRequest,
18 } from '../../../lib/attachments/attachment-write.mjs';
19 import { getProposal, updateProposalStatus } from '../../../hub/proposals-store.mjs';
20 import { noteStateIdFromParts } from '../../../lib/note-state-id.mjs';
21 import { readNote } from '../../../lib/vault.mjs';
22 import { buildAttachmentFixtureVault } from '../attachment-fixture.mjs';
23
24 export const visibleAll = new Set(['personal', 'project', 'org']);
25
26 /**
27 * @param {string} tmpRoot
28 * @returns {ReturnType<typeof buildAttachmentFixtureVault> & { targetNoteRef: string, targetNotePath: string, targetBaseStateId: string }}
29 */
30 export function buildMediaWriteFixture(tmpRoot) {
31 const fx = buildAttachmentFixtureVault(tmpRoot);
32 const targetNotePath = 'target-lesson.md';
33 fs.writeFileSync(
34 path.join(fx.vaultPath, targetNotePath),
35 `---
36 title: Target Lesson
37 ---
38 # Lesson body
39 `,
40 );
41 const note = readNote(fx.vaultPath, targetNotePath);
42 const targetNoteRef = 'note:target-lesson.md';
43 const targetBaseStateId = noteStateIdFromParts(note.frontmatter ?? {}, note.body ?? '');
44
45 seedConnectorAllowlist(fx.dataDir, fx.vaultId, { gdrive: true });
46 return { ...fx, targetNoteRef, targetNotePath, targetBaseStateId };
47 }
48
49 /**
50 * @param {string} dataDir
51 * @param {string} vaultId
52 * @param {Record<string, boolean>} connectors
53 */
54 export function seedConnectorAllowlist(dataDir, vaultId, connectors) {
55 const store = loadMediaConnectorPolicy(dataDir);
56 if (!store.vaults[vaultId]) store.vaults[vaultId] = { connectors: {} };
57 const now = new Date().toISOString();
58 for (const [id, enabled] of Object.entries(connectors)) {
59 store.vaults[vaultId].connectors[id] = {
60 enabled: enabled === true,
61 display_name: id,
62 updated: now,
63 };
64 }
65 saveMediaConnectorPolicy(dataDir, store);
66 }
67
68 /**
69 * @param {string} dataDir
70 * @param {string} vaultId
71 * @param {string} connectorId
72 * @param {string} scope
73 */
74 export function grantActiveConsent(dataDir, vaultId, connectorId, scope = 'personal') {
75 const result = handleMediaImportConsentGrantRequest({
76 dataDir,
77 vaultId,
78 userId: 'test-user',
79 cliScopes: ['personal', 'project', 'org'],
80 body: { connector_id: connectorId, scope, expires_at: null },
81 });
82 if (!result.ok) throw new Error(result.error);
83 return result.payload.consent_id;
84 }
85
86 /**
87 * @param {string} dataDir
88 * @param {string} proposalId
89 * @param {string} vaultPath
90 * @param {object} [vaultConfig]
91 */
92 export function approveMediaProposal(dataDir, proposalId, vaultPath, vaultConfig = {}) {
93 const proposal = getProposal(dataDir, proposalId);
94 const pre = precheckApprovedMediaProposal(dataDir, proposal, { vaultPath, vaultConfig });
95 if (!pre.ok) return pre;
96 reconcileApprovedMediaProposal(dataDir, pre);
97 updateProposalStatus(dataDir, proposalId, 'approved');
98 return { ok: true, pre };
99 }
100
101 /**
102 * @param {object} [overrides]
103 */
104 export function sampleLinkProposeBody(overrides = {}) {
105 const connectorId = 'gdrive';
106 const opaqueRef = overrides.opaque_ref ?? '1AbCd_efGhIjkLmnOpQrStU';
107 return {
108 scope: 'personal',
109 connector_id: connectorId,
110 opaque_ref: opaqueRef,
111 consent_id: overrides.consent_id ?? 'mic_0123456789abcdef',
112 display_label: 'Design board',
113 attachment_id: deriveLinkAttachmentId(connectorId, opaqueRef),
114 ...overrides,
115 };
116 }
117
118 /**
119 * @param {object} fx
120 * @param {object} [overrides]
121 */
122 export function sampleAttachProposeBody(fx, overrides = {}) {
123 return {
124 scope: 'personal',
125 attachment_id: fx.fileId,
126 note_ref: fx.targetNoteRef,
127 base_state_id: fx.targetBaseStateId,
128 ...overrides,
129 };
130 }
File History 1 commit
sha256:93bcf8f9bd56d8c5b9339f4ec73b9ebd66571398d56262d38eedc2cfa9db9882 fix(test): align Band B landing assertion with desktop MCP … Human 11 days ago