Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ npm start # indexer + read API
# or run separately:
npm run index # indexer only
npm run serve # read API only

# indexer flags (override the matching env var; see --help):
node index.js --hoses profiles --no-legacy # run a single hose, no legacy fallback
node src/indexer.js --help
```

## Read API
Expand Down
6 changes: 4 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Entry point: run the read API and the relay indexer in one process.
import { startServer } from './src/server.js';
import { runIndexer } from './src/indexer.js';
import { runIndexer, parseArgs, USAGE } from './src/indexer.js';

if (parseArgs().help) { console.log(USAGE); process.exit(0); }

await startServer();
await runIndexer();
await runIndexer(); // honours --hoses / --legacy / --no-legacy (override env)
41 changes: 39 additions & 2 deletions src/indexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,38 @@ export function planIngest(allHoses = ALL_HOSES, env = process.env, legacyKindsA
const SUB_ID = 'beacon';
const RECONNECT_MS = 3000;

export const USAGE = `beacon indexer — firehose into MongoDB

Usage: node index.js [flags] (or: node src/indexer.js [flags])

Flags (override the matching env var):
--hoses <list> comma list of hose names to run (env HOSES; default: all)
--no-legacy disable the raw-upsert fallback for un-migrated kinds (INDEX_LEGACY_KINDS=0)
--legacy force the legacy fallback on
-h, --help show this help

Env: MONGODB_URI, MONGO_DB, RELAYS, PORT — see .env.example`;

/**
* Parse indexer CLI flags into an env-overlay (only keys the user passed).
* Merged over process.env by runIndexer so flags win and env is the fallback.
*/
export function parseArgs(argv = process.argv.slice(2)) {
const out = {};
for (let i = 0; i < argv.length; i++) {
const a = argv[i];
if (a === '-h' || a === '--help') out.help = true;
else if (a === '--no-legacy') out.INDEX_LEGACY_KINDS = '0';
else if (a === '--legacy') out.INDEX_LEGACY_KINDS = '1';
else if (a === '--hoses' || a.startsWith('--hoses=')) {
const next = argv[i + 1];
out.HOSES = a.includes('=') ? a.slice(a.indexOf('=') + 1)
: (next && !next.startsWith('--') ? argv[++i] : '');
}
}
return out;
}

function connectRelay(url, kinds, onEvent) {
let ws, closed = false, timer;
const open = () => {
Expand All @@ -63,7 +95,9 @@ function connectRelay(url, kinds, onEvent) {

export async function runIndexer() {
const db = await connect();
const { hoses, hoseFor, kinds, legacy, unknown } = planIngest();
// CLI flags override env; env (process.env / .env) is the fallback.
const env = { ...process.env, ...parseArgs() };
const { hoses, hoseFor, kinds, legacy, unknown } = planIngest(ALL_HOSES, env);
if (unknown.length) console.warn(`[beacon] unknown hose(s) in HOSES, ignored: ${unknown.join(', ')}`);
if (!kinds.length) { console.warn('[beacon] no hoses enabled and no legacy kinds — nothing to index'); return { stop() {} }; }
for (const h of hoses) await h.ensureIndexes(db);
Expand All @@ -87,4 +121,7 @@ export async function runIndexer() {
return { stop };
}

if (import.meta.url === `file://${process.argv[1]}`) runIndexer();
if (import.meta.url === `file://${process.argv[1]}`) {
if (parseArgs().help) { console.log(USAGE); process.exit(0); }
runIndexer();
}
50 changes: 50 additions & 0 deletions test/indexer-args.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// CLI flag parsing for the indexer. parseArgs produces an env-overlay that
// runIndexer merges over process.env (flags win, env is the fallback).
import test from 'node:test';
import assert from 'node:assert/strict';
import { parseArgs, planIngest } from '../src/indexer.js';

const profiles = { name: 'profiles', kinds: [0] };
const follows = { name: 'follows', kinds: [3] };
const ALL = [profiles, follows];

test('no flags -> empty overlay', () => {
assert.deepEqual(parseArgs([]), {});
});

test('--hoses with a space-separated value', () => {
assert.deepEqual(parseArgs(['--hoses', 'profiles,follows']), { HOSES: 'profiles,follows' });
});

test('--hoses=value form', () => {
assert.deepEqual(parseArgs(['--hoses=profiles']), { HOSES: 'profiles' });
});

test('--hoses with no value -> empty string (planIngest treats as default)', () => {
assert.deepEqual(parseArgs(['--hoses']), { HOSES: '' });
assert.deepEqual(parseArgs(['--hoses', '--no-legacy']), { HOSES: '', INDEX_LEGACY_KINDS: '0' });
});

test('--no-legacy and --legacy map to INDEX_LEGACY_KINDS', () => {
assert.deepEqual(parseArgs(['--no-legacy']), { INDEX_LEGACY_KINDS: '0' });
assert.deepEqual(parseArgs(['--legacy']), { INDEX_LEGACY_KINDS: '1' });
});

test('--help / -h set help', () => {
assert.equal(parseArgs(['--help']).help, true);
assert.equal(parseArgs(['-h']).help, true);
});

test('flags compose', () => {
assert.deepEqual(parseArgs(['--hoses', 'profiles', '--no-legacy']),
{ HOSES: 'profiles', INDEX_LEGACY_KINDS: '0' });
});

test('flags override env when merged (the runIndexer contract)', () => {
const env = { HOSES: 'profiles,follows', INDEX_LEGACY_KINDS: '1' };
const merged = { ...env, ...parseArgs(['--hoses', 'profiles', '--no-legacy']) };
const p = planIngest(ALL, merged, []);
assert.deepEqual(p.hoses.map((h) => h.name), ['profiles']); // flag won over env
assert.equal(p.legacy, false);
assert.deepEqual(p.kinds, [0]);
});