feat(rcred): auto-seed demo scores on startup + open recompute for demo
Triggers recomputeSpace('demo') 10s after init if no scores exist.
Allows unauthenticated recompute on demo space so visitors can click
the Recompute button.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
030d69b29f
commit
f2b125a72f
|
|
@ -13,7 +13,7 @@ import { renderShell } from '../../server/shell';
|
||||||
import { getModuleInfoList } from '../../shared/module';
|
import { getModuleInfoList } from '../../shared/module';
|
||||||
import type { RSpaceModule } from '../../shared/module';
|
import type { RSpaceModule } from '../../shared/module';
|
||||||
import type { SyncServer } from '../../server/local-first/sync-server';
|
import type { SyncServer } from '../../server/local-first/sync-server';
|
||||||
import { graphSchema, scoresSchema, configSchema, configDocId } from './schemas';
|
import { graphSchema, scoresSchema, configSchema, configDocId, scoresDocId } from './schemas';
|
||||||
import type { CredConfigDoc } from './schemas';
|
import type { CredConfigDoc } from './schemas';
|
||||||
import { createCredRoutes } from './routes';
|
import { createCredRoutes } from './routes';
|
||||||
import { recomputeSpace, ensureConfigDoc } from './grain-engine';
|
import { recomputeSpace, ensureConfigDoc } from './grain-engine';
|
||||||
|
|
@ -83,6 +83,16 @@ export const credModule: RSpaceModule = {
|
||||||
_syncServer = syncServer;
|
_syncServer = syncServer;
|
||||||
startCredCron();
|
startCredCron();
|
||||||
console.log('[rCred] Module initialized, cron started (6h interval)');
|
console.log('[rCred] Module initialized, cron started (6h interval)');
|
||||||
|
|
||||||
|
// Auto-seed demo space on startup (delayed to let docs load)
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!_syncServer) return;
|
||||||
|
const scores = _syncServer.getDoc(scoresDocId('demo'));
|
||||||
|
if (!scores) {
|
||||||
|
console.log('[rCred] Seeding demo space scores...');
|
||||||
|
recomputeSpace('demo', _syncServer);
|
||||||
|
}
|
||||||
|
}, 10_000);
|
||||||
},
|
},
|
||||||
|
|
||||||
feeds: [
|
feeds: [
|
||||||
|
|
|
||||||
|
|
@ -136,19 +136,22 @@ export function createCredRoutes(getSyncServer: () => SyncServer | null) {
|
||||||
return c.json({ ok: true });
|
return c.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── POST /api/recompute — trigger immediate recompute (auth required) ──
|
// ── POST /api/recompute — trigger immediate recompute ──
|
||||||
|
// Demo space: open access. Other spaces: require member+ auth.
|
||||||
routes.post('/api/recompute', async (c) => {
|
routes.post('/api/recompute', async (c) => {
|
||||||
const space = c.req.param('space') || c.req.query('space') || '';
|
const space = c.req.param('space') || c.req.query('space') || '';
|
||||||
if (!space) return c.json({ error: 'space required' }, 400);
|
if (!space) return c.json({ error: 'space required' }, 400);
|
||||||
|
|
||||||
const token = extractToken(c.req.raw.headers);
|
if (space !== 'demo') {
|
||||||
if (!token) return c.json({ error: 'Auth required' }, 401);
|
const token = extractToken(c.req.raw.headers);
|
||||||
const claims = await verifyToken(token);
|
if (!token) return c.json({ error: 'Auth required' }, 401);
|
||||||
if (!claims) return c.json({ error: 'Invalid token' }, 401);
|
const claims = await verifyToken(token);
|
||||||
|
if (!claims) return c.json({ error: 'Invalid token' }, 401);
|
||||||
|
|
||||||
const resolved = await resolveCallerRole(space, claims);
|
const resolved = await resolveCallerRole(space, claims);
|
||||||
if (!resolved || resolved.role === 'viewer') {
|
if (!resolved || resolved.role === 'viewer') {
|
||||||
return c.json({ error: 'Membership required' }, 403);
|
return c.json({ error: 'Membership required' }, 403);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = recomputeSpace(space, ss());
|
const result = recomputeSpace(space, ss());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue