Major Changes: - Moved legacy system to Legacy/ folder for archival - Built new modular architecture with strict separation of concerns - Created core system: Module, EventBus, ModuleLoader, Router - Added Application bootstrap with auto-start functionality - Implemented development server with ES6 modules support - Created comprehensive documentation and project context - Converted SBS-7-8 content to JSON format - Copied all legacy games and content to new structure New Architecture Features: - Sealed modules with WeakMap private data - Strict dependency injection system - Event-driven communication only - Inviolable responsibility patterns - Auto-initialization without commands - Component-based UI foundation ready Technical Stack: - Vanilla JS/HTML/CSS only - ES6 modules with proper imports/exports - HTTP development server (no file:// protocol) - Modular CSS with component scoping - Comprehensive error handling and debugging Ready for Phase 2: Converting legacy modules to new architecture 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
106 lines
3.6 KiB
JavaScript
106 lines
3.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const crypto = require('crypto');
|
|
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
|
|
// Ta configuration
|
|
const config = {
|
|
DO_ACCESS_KEY: 'DO801MU8BZBB89LLK4FN',
|
|
DO_SECRET_KEY: 'rfKPjampdpUCYhn02XrKg6IWKmqebjg9HQTGxNLzJQY',
|
|
DO_REGION: 'fra1',
|
|
DO_ENDPOINT: 'https://autocollant.fra1.digitaloceanspaces.com',
|
|
DO_CONTENT_PATH: 'Class_generator/ContentMe'
|
|
};
|
|
|
|
function sha256(message) {
|
|
return crypto.createHash('sha256').update(message, 'utf8').digest('hex');
|
|
}
|
|
|
|
function hmacSha256(key, message) {
|
|
return crypto.createHmac('sha256', key).update(message, 'utf8').digest();
|
|
}
|
|
|
|
async function generateAWSSignature(method, url) {
|
|
const now = new Date();
|
|
const dateStamp = now.toISOString().slice(0, 10).replace(/-/g, '');
|
|
const timeStamp = now.toISOString().slice(0, 19).replace(/[-:]/g, '') + 'Z';
|
|
|
|
const urlObj = new URL(url);
|
|
const host = urlObj.hostname;
|
|
const canonicalUri = urlObj.pathname;
|
|
const canonicalQueryString = urlObj.search ? urlObj.search.slice(1) : '';
|
|
|
|
const canonicalHeaders = `host:${host}\nx-amz-date:${timeStamp}\n`;
|
|
const signedHeaders = 'host;x-amz-date';
|
|
|
|
const payloadHash = method === 'GET' ? sha256('') : 'UNSIGNED-PAYLOAD';
|
|
const canonicalRequest = [
|
|
method,
|
|
canonicalUri,
|
|
canonicalQueryString,
|
|
canonicalHeaders,
|
|
signedHeaders,
|
|
payloadHash
|
|
].join('\n');
|
|
|
|
const algorithm = 'AWS4-HMAC-SHA256';
|
|
const credentialScope = `${dateStamp}/${config.DO_REGION}/s3/aws4_request`;
|
|
const canonicalRequestHash = sha256(canonicalRequest);
|
|
const stringToSign = [
|
|
algorithm,
|
|
timeStamp,
|
|
credentialScope,
|
|
canonicalRequestHash
|
|
].join('\n');
|
|
|
|
const kDate = hmacSha256('AWS4' + config.DO_SECRET_KEY, dateStamp);
|
|
const kRegion = hmacSha256(kDate, config.DO_REGION);
|
|
const kService = hmacSha256(kRegion, 's3');
|
|
const kSigning = hmacSha256(kService, 'aws4_request');
|
|
const signature = hmacSha256(kSigning, stringToSign).toString('hex');
|
|
|
|
const authorization = `${algorithm} Credential=${config.DO_ACCESS_KEY}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
|
|
return {
|
|
'Authorization': authorization,
|
|
'X-Amz-Date': timeStamp,
|
|
'X-Amz-Content-Sha256': payloadHash
|
|
};
|
|
}
|
|
|
|
async function testDigitalOceanFetch() {
|
|
console.log('🚀 Test DigitalOcean avec node-fetch\n');
|
|
|
|
const testUrl = `${config.DO_ENDPOINT}/${config.DO_CONTENT_PATH}/english-class-demo.json`;
|
|
console.log(`🎯 URL: ${testUrl}`);
|
|
|
|
try {
|
|
const headers = await generateAWSSignature('GET', testUrl);
|
|
console.log('🔐 Headers générés:', JSON.stringify(headers, null, 2));
|
|
|
|
console.log('\n🌐 Requête fetch...');
|
|
const response = await fetch(testUrl, {
|
|
method: 'GET',
|
|
headers: headers
|
|
});
|
|
|
|
console.log(`📡 Status: ${response.status} ${response.statusText}`);
|
|
console.log(`📝 Headers response:`, Object.fromEntries(response.headers.entries()));
|
|
|
|
if (response.ok) {
|
|
const content = await response.text();
|
|
console.log(`✅ SUCCÈS ! Contenu (${content.length} chars):`);
|
|
console.log(content.substring(0, 500) + '...');
|
|
} else {
|
|
const errorText = await response.text();
|
|
console.log(`❌ Erreur: ${errorText}`);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(`💥 Erreur fetch: ${error.message}`);
|
|
console.error(error.stack);
|
|
}
|
|
}
|
|
|
|
// Lancer le test
|
|
testDigitalOceanFetch(); |