feat: rebrand Hemmelig to paste.es for cloudhost.es
- Set Spanish as default language with ephemeral/encrypted privacy focus - Translate all user-facing strings and legal pages to Spanish - Replace Norwegian flag with Spanish flag in footer - Remove Hemmelig/terces.cloud links, add cloudhost.es sponsorship - Rewrite PrivacyPage: zero data collection, ephemeral design emphasis - Rewrite TermsPage: Spanish law, RGPD, paste.es/CloudHost.es references - Update PWA manifest, HTML meta tags, package.json branding - Rename webhook headers to X-Paste-Event / X-Paste-Signature - Update API docs title and contact to paste.es / cloudhost.es Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
205
scripts/seed-demo.ts
Normal file
205
scripts/seed-demo.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import crypto from 'crypto';
|
||||
import db from '../api/lib/db';
|
||||
|
||||
const DAYS_TO_GENERATE = 30;
|
||||
const VISITOR_PATHS = ['/', '/secret'];
|
||||
|
||||
function randomInt(min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function randomDate(daysAgo: number): Date {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - daysAgo);
|
||||
date.setHours(randomInt(0, 23), randomInt(0, 59), randomInt(0, 59));
|
||||
return date;
|
||||
}
|
||||
|
||||
function generateUniqueVisitorId(): string {
|
||||
return crypto.randomBytes(16).toString('hex');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Instance Settings
|
||||
// ============================================
|
||||
async function seedInstanceSettings() {
|
||||
console.log('Seeding instance settings...');
|
||||
|
||||
const existing = await db.instanceSettings.findFirst();
|
||||
if (existing) {
|
||||
console.log(' Instance settings already exist, skipping...');
|
||||
console.log(' Done!\n');
|
||||
return existing;
|
||||
}
|
||||
|
||||
const settings = await db.instanceSettings.create({
|
||||
data: {
|
||||
instanceName: 'Hemmelig Demo',
|
||||
instanceDescription: 'A demo instance of Hemmelig for testing and development.',
|
||||
allowRegistration: true,
|
||||
requireEmailVerification: false,
|
||||
defaultSecretExpiration: 72,
|
||||
maxSecretSize: 1024,
|
||||
allowPasswordProtection: true,
|
||||
allowIpRestriction: true,
|
||||
enableRateLimiting: true,
|
||||
rateLimitRequests: 100,
|
||||
rateLimitWindow: 60,
|
||||
requireInviteCode: false,
|
||||
webhookEnabled: false,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(' Created instance settings');
|
||||
console.log(' Done!\n');
|
||||
return settings;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Secrets
|
||||
// ============================================
|
||||
async function seedSecrets() {
|
||||
console.log('Seeding secrets...');
|
||||
|
||||
const records = [];
|
||||
|
||||
for (let daysAgo = 0; daysAgo < DAYS_TO_GENERATE; daysAgo++) {
|
||||
// Generate between 1-15 secrets per day
|
||||
const secretsCount = randomInt(1, 15);
|
||||
|
||||
for (let i = 0; i < secretsCount; i++) {
|
||||
const createdAt = randomDate(daysAgo);
|
||||
|
||||
// Random expiration: 1 hour, 1 day, 1 week, or more
|
||||
const expirationHours = [1, 24, 168, 336, 672][randomInt(0, 4)];
|
||||
const expiresAt = new Date(createdAt.getTime() + expirationHours * 60 * 60 * 1000);
|
||||
|
||||
// Random features
|
||||
const hasPassword = Math.random() < 0.3;
|
||||
const hasIpRange = Math.random() < 0.1;
|
||||
const isBurnable = Math.random() < 0.4;
|
||||
|
||||
// Random views
|
||||
const views = randomInt(1, 20);
|
||||
|
||||
// Generate dummy encrypted data
|
||||
const secret = Buffer.from(crypto.randomBytes(32));
|
||||
const title = Buffer.from(crypto.randomBytes(16));
|
||||
const salt = crypto.randomBytes(16).toString('hex');
|
||||
|
||||
records.push({
|
||||
secret,
|
||||
title,
|
||||
salt,
|
||||
views,
|
||||
password: hasPassword ? crypto.randomBytes(32).toString('hex') : null,
|
||||
ipRange: hasIpRange ? '192.168.1.0/24' : '',
|
||||
isBurnable,
|
||||
createdAt,
|
||||
expiresAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Batch insert
|
||||
const batchSize = 100;
|
||||
for (let i = 0; i < records.length; i += batchSize) {
|
||||
const batch = records.slice(i, i + batchSize);
|
||||
await db.secrets.createMany({ data: batch });
|
||||
process.stdout.write(
|
||||
`\r Created ${Math.min(i + batchSize, records.length)}/${records.length} secrets`
|
||||
);
|
||||
}
|
||||
|
||||
console.log('\n Done!\n');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Visitor Analytics
|
||||
// ============================================
|
||||
async function seedVisitorAnalytics() {
|
||||
console.log('Seeding visitor analytics...');
|
||||
|
||||
const records = [];
|
||||
|
||||
for (let daysAgo = 0; daysAgo < DAYS_TO_GENERATE; daysAgo++) {
|
||||
// Generate between 5-50 unique visitors per day
|
||||
const uniqueVisitors = randomInt(5, 50);
|
||||
const visitorIds = Array.from({ length: uniqueVisitors }, () => generateUniqueVisitorId());
|
||||
|
||||
for (const visitorId of visitorIds) {
|
||||
// Each visitor views 1-5 pages
|
||||
const pageViews = randomInt(1, 5);
|
||||
|
||||
for (let i = 0; i < pageViews; i++) {
|
||||
const path = VISITOR_PATHS[randomInt(0, VISITOR_PATHS.length - 1)];
|
||||
records.push({
|
||||
path,
|
||||
uniqueId: visitorId,
|
||||
timestamp: randomDate(daysAgo),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Batch insert
|
||||
const batchSize = 500;
|
||||
for (let i = 0; i < records.length; i += batchSize) {
|
||||
const batch = records.slice(i, i + batchSize);
|
||||
await db.visitorAnalytics.createMany({ data: batch });
|
||||
process.stdout.write(
|
||||
`\r Created ${Math.min(i + batchSize, records.length)}/${records.length} visitor records`
|
||||
);
|
||||
}
|
||||
|
||||
console.log('\n Done!\n');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Clear Data
|
||||
// ============================================
|
||||
async function clearDemoData() {
|
||||
console.log('Clearing existing demo data...');
|
||||
|
||||
await db.visitorAnalytics.deleteMany({});
|
||||
console.log(' Cleared visitor analytics');
|
||||
|
||||
// Only delete anonymous secrets (no userId)
|
||||
await db.secrets.deleteMany({ where: { userId: null } });
|
||||
console.log(' Cleared anonymous secrets');
|
||||
|
||||
await db.instanceSettings.deleteMany({});
|
||||
console.log(' Cleared instance settings');
|
||||
|
||||
console.log(' Done!\n');
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Main
|
||||
// ============================================
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const shouldClear = args.includes('--clear');
|
||||
|
||||
console.log('\n🌱 Hemmelig Demo Database Seeder\n');
|
||||
console.log('This will populate the database with demo data for development.\n');
|
||||
|
||||
try {
|
||||
if (shouldClear) {
|
||||
await clearDemoData();
|
||||
}
|
||||
|
||||
await seedInstanceSettings();
|
||||
await seedSecrets();
|
||||
await seedVisitorAnalytics();
|
||||
|
||||
console.log('✅ Demo database seeded successfully!\n');
|
||||
} catch (error) {
|
||||
console.error('\n❌ An error occurred:', error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await db.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user