Story 4.1: Task 1 Complete - PlayerPrivacyManager Core Logic

- Created src/contracts/privacy-settings.js with:
  - PrivacySettings typedef
  - PRIVACY_SETTINGS_DEFAULT (both flags false)
  - PRIVACY_SETTING_KEYS and FEATURE_NAME_MAP constants
  - createPrivacySettings() factory
  - isValidPrivacySettings() validator
  - validateSettingKey(), validateSettingValue(), validateFeatureName() helpers
- Created src/core/PlayerPrivacyManager.js with:
  - Constructor with FoundryAdapter DI validation
  - getSettings(userId) - retrieves settings from user flags
  - setSetting(userId, key, value) - async, validates, persists via user.setFlag
  - isOptedIn(userId, feature) - convenience method for feature checks
  - getAllSettings() - aggregates all users' settings (GM view)
  - onChange(callback) - subscription pattern for change events
  - teardown() - cleanup
- Created tests/unit/contracts/privacy-settings.test.js - 44 tests
- Created tests/unit/core/PlayerPrivacyManager.test.js - 35 tests
- All tests passing, lint clean
- Updated sprint-status.yaml: 4-1 from ready-for-dev to in-progress
- Updated story file: Task 1 subtasks 1.1-1.8 marked complete

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-05-23 21:11:55 +02:00
parent e81c05a3db
commit 61f362004e
13 changed files with 1971 additions and 29 deletions
@@ -0,0 +1,105 @@
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:9222/devtools/page/992C42C102A9604DCB6F7EE5CE6A5048');
console.log('\n========================================');
console.log('Epic 3 Live Tests - Scene Presets');
console.log('========================================\n');
const tests = [
{
id: 1,
name: 'Module is active',
expr: 'game.modules.get("video-view-manager").active'
},
{
id: 2,
name: 'User is GM',
expr: 'game.user.isGM'
},
{
id: 3,
name: 'Current scene exists',
expr: '!!game.scenes.current'
},
{
id: 4,
name: 'Can read scene flags',
expr: '(typeof game.scenes.current.getFlag === "function")'
},
{
id: 5,
name: 'Can write scene flags',
expr: '(typeof game.scenes.current.setFlag === "function")'
},
{
id: 6,
name: 'ui.notifications exists',
expr: '!!ui.notifications'
},
{
id: 7,
name: 'Hooks exists',
expr: '!!Hooks'
},
{
id: 8,
name: 'game.webrtc exists',
expr: 'game.webrtc !== undefined'
}
];
let currentTest = 0;
ws.on('open', () => {
console.log('✓ Connected to Foundry page\n');
runNextTest();
});
function runNextTest() {
if (currentTest >= tests.length) {
console.log('\n========================================');
console.log('✓ All environment tests passed!');
console.log('========================================\n');
console.log('Summary:');
console.log('- FoundryVTT is running with module active');
console.log('- User is GM (required for most Epic 3 features)');
console.log('- Scene flag API is available');
console.log('- Notification system is available');
console.log('- Hooks system is available');
console.log('\n✓ Environment is ready for Epic 3 testing!\n');
ws.close();
return;
}
const test = tests[currentTest];
ws.send(JSON.stringify({
id: test.id,
method: 'Runtime.evaluate',
params: { expression: test.expr }
}));
}
ws.on('message', (data) => {
try {
const response = JSON.parse(data);
const test = tests.find(t => t.id === response.id);
if (test) {
const value = response.result?.result?.value;
const passed = value === true || value === 'function' || value === 'object';
const status = passed ? '✓' : '✗';
console.log(`${status} ${test.name}`);
currentTest++;
runNextTest();
}
} catch (e) {
console.error('Error parsing response:', e.message);
}
});
ws.on('error', (e) => {
console.error('✗ WebSocket error:', e.message);
ws.close();
});