Compare commits

..

3 Commits

Author SHA1 Message Date
Levente Orban
a1fa879f36 fix: improve the federation.config 2025-11-10 11:46:02 +01:00
Levente Orban
b723aac180 fix: federation config refactor 2025-11-10 10:14:44 +01:00
Levente Orban
277ad3ff14 feat: add db-seed to makefile and merge migrations 2025-11-10 10:01:23 +01:00
8 changed files with 34 additions and 77 deletions

View File

@@ -10,4 +10,14 @@ APP_VERSION=latest
PORT=5173
HOSTNAME=0.0.0.0
# Logger configuration
LOG_PRETTY=true
LOG_LEVEL="trace"
# If you don't want to use the default home page you can turn off
# in this case the /discovery page remain the home of your site
PUBLIC_LANDING_INFO=true
# Federation config
FEDERATION_INSTANCE=false

View File

@@ -59,6 +59,17 @@ make db-only
npm run dev -- --open
```
#### Build the image in local
```
docker build \
--build-arg LOG_PRETTY=${LOG_PRETTY:-true} \
--build-arg LOG_LEVEL=${LOG_LEVEL:-trace} \
--build-arg PUBLIC_LANDING_INFO=${PUBLIC_LANDING_INFO:-true} \
--build-arg FEDERATION_INSTANCE=${FEDERATION_INSTANCE:-true} \
-t cactoide-example .
```
Your app will be available at `http://localhost:5173`. You can use the Makefile commands to run the application or the database, eg.: `make db-only`.
Use the `database/seed.sql` if you want to populate your database with dummy data.
@@ -103,12 +114,12 @@ Your instance will automatically expose:
To add your instance to the global federation list (so other instances can discover your events):
1. Fork the [Cactoide repository](https://github.com/polaroi8d/cactoide)
2. Add your instance URL to the `instances` array in [`federation.config.js`](https://github.com/polaroi8d/cactoide/blob/main/federation.config.js):
2. Add your instance URL to the `instances` array in `federation.config.js`:
3. Open a pull request to the main repository
Once merged, your instance will appear in the federation network, and other instances will be able to discover and display your public events.
You can view all registered federated instances in the main repository: [`federation.config.js`](https://github.com/polaroi8d/cactoide/blob/main/federation.config.js) file.
You can view all registered federated instances in the main repository: `federation.config.js` file.
### Options

View File

@@ -37,6 +37,10 @@ services:
DATABASE_URL: ${DATABASE_URL:-postgres://cactoide:cactoide_password@postgres:5432/cactoide_database}
PORT: 3000
HOSTNAME: ${HOSTNAME:-0.0.0.0}
LOG_PRETTY: ${LOG_PRETTY:-true}
LOG_LEVEL: ${LOG_LEVEL:-trace}
PUBLIC_LANDING_INFO: ${PUBLIC_LANDING_INFO:-true}
FEDERATION_INSTANCE: ${FEDERATION_INSTANCE:-true}
depends_on:
postgres:
condition: service_healthy

View File

@@ -1,9 +1,9 @@
const config = {
name: 'Cactoide Genesis',
instances: [
{
url: 'cactoide.org'
}
// {
// url: 'cactoide.org'
// }
// {
// url: 'YOUR_INSTANCE_URL'
// }

View File

@@ -1,76 +1,18 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { logger } from '$lib/logger';
import type { Event } from '$lib/types';
import config from '../../federation.config.js';
console.log(config.instances);
interface FederationConfig {
name: string;
instances: Array<{ url: string }>;
}
import config from '$lib/config/federation.config.js';
interface FederationEventsResponse {
events: Array<Event & { federation?: boolean }>;
count?: number;
}
/**
* Reads the federation config file
*/
async function readFederationConfig(): Promise<FederationConfig | null> {
try {
const configPath = join(process.cwd(), 'federation.config.js');
// Use dynamic import to load the config file as a module
// This is safer than eval and works with ES modules
const configModule = await import(configPath + '?t=' + Date.now());
const config = (configModule.default || configModule.config) as FederationConfig;
if (config && config.instances && Array.isArray(config.instances)) {
return config;
}
logger.warn('Invalid federation config structure');
return null;
} catch (error) {
// If dynamic import fails, try reading as text and parsing
try {
const configPath = join(process.cwd(), 'federation.config.js');
const configContent = readFileSync(configPath, 'utf-8');
// Try to extract JSON-like structure
const configMatch = configContent.match(/instances:\s*\[([\s\S]*?)\]/);
if (configMatch) {
// Simple parsing - extract URLs
const urlMatches = configContent.matchAll(/url:\s*['"]([^'"]+)['"]/g);
const instances = Array.from(urlMatches, (match) => ({ url: match[1] }));
if (instances.length > 0) {
return {
name: 'Federated Instances',
instances
};
}
}
} catch (fallbackError) {
logger.error({ error: fallbackError }, 'Error parsing federation.config.js as fallback');
}
logger.error({ error }, 'Error reading federation.config.js');
return null;
}
}
/**
* Fetches events from a single federated instance
*/
async function fetchEventsFromInstance(instanceUrl: string): Promise<Event[]> {
try {
// Ensure URL has protocol and append /api/federation/events
const apiUrl = `http://${instanceUrl}/api/federation/events`;
logger.debug({ apiUrl }, 'Fetching events from federated instance');
@@ -120,18 +62,11 @@ async function fetchEventsFromInstance(instanceUrl: string): Promise<Event[]> {
* Fetches events from all configured federated instances
*/
export async function fetchAllFederatedEvents(): Promise<Event[]> {
const config = await readFederationConfig();
if (!config || !config.instances || config.instances.length === 0) {
logger.debug('No federation config or instances found');
return [];
}
logger.info(
{ instanceCount: config.instances.length },
'Fetching events from federated instances'
);
// Fetch from all instances in parallel
const fetchPromises = config.instances.map((instance) => fetchEventsFromInstance(instance.url));

View File

@@ -4,7 +4,7 @@ import { database } from '$lib/database/db';
import { events } from '$lib/database/schema';
import { eq, count } from 'drizzle-orm';
import { logger } from '$lib/logger';
import federationConfig from '../../../../../federation.config.js';
import federationConfig from '$lib/config/federation.config.js';
import { FEDERATION_INSTANCE } from '$env/static/private';

View File

@@ -1,6 +1,6 @@
import type { PageServerLoad } from './$types';
import { logger } from '$lib/logger';
import federationConfig from '../../../federation.config.js';
import federationConfig from '$lib/config/federation.config.js';
interface InstanceInfo {
name: string;

View File

@@ -130,10 +130,7 @@
<p class="py-8 text-center text-slate-400">
{t('instance.description')}
<a
href="https://github.com/cactoide/cactoide/blob/main/federation.config.js"
class="text-violet-300/80">{t('instance.configFile')}</a
>
{t('instance.configFile')}
{t('instance.file')}
</p>