P4-B: notifications Web Push (VAPID) sur passage en waiting
- db: migration id=4 `push_subscriptions` (liées au token d'auth) ; clés VAPID en settings - PushService: bootstrap idempotent des clés VAPID, subscribe/unsubscribe/count, notify() best-effort (purge des abonnements 410/404 Gone) ; sender injectable pour les tests - routes/push.ts: GET vapid-public-key, POST subscribe/unsubscribe/test (toutes sous auth globale) - pty-manager: déclencheur push sur FRONT MONTANT vers waiting, débouncé 1500ms et annulable (faux positif ignoré) ; câblage app/index/config (--vapid-contact) - shared/api.ts: types VapidKeyResponse / PushSubscribeRequest / PushUnsubscribeRequest - deps: web-push (+ @types/web-push) côté serveur - tests: push-service (idempotence, UPSERT, 410-purge, payload) + trigger pty-manager (169 verts)
This commit is contained in:
@@ -11,10 +11,12 @@ import { AuthService, LoginRateLimiter, type AuthContext } from './auth/service.
|
||||
import { PtyManager } from './core/pty-manager.js';
|
||||
import { DiscoveryService } from './core/discovery-service.js';
|
||||
import { WorktreeManager } from './core/worktree-manager.js';
|
||||
import { PushService } from './core/push-service.js';
|
||||
import { registerAuthRoutes } from './routes/auth.js';
|
||||
import { registerSessionRoutes } from './routes/sessions.js';
|
||||
import { registerRepoRoutes } from './routes/repos.js';
|
||||
import { registerWorktreeRoutes } from './routes/worktrees.js';
|
||||
import { registerPushRoutes } from './routes/push.js';
|
||||
import { registerWsGateway } from './ws/gateway.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
@@ -32,13 +34,15 @@ export interface AppBundle {
|
||||
manager: PtyManager;
|
||||
discovery: DiscoveryService;
|
||||
worktrees: WorktreeManager;
|
||||
push: PushService;
|
||||
}
|
||||
|
||||
export function buildApp(config: Config, db: Db, serverVersion: string): AppBundle {
|
||||
const app = Fastify({ logger: { level: process.env.ARBORETUM_LOG ?? 'info' } });
|
||||
const auth = new AuthService(db);
|
||||
const limiter = new LoginRateLimiter();
|
||||
const manager = new PtyManager(db, config.claudeSessionsDir);
|
||||
const push = new PushService(db, config.vapidContact);
|
||||
const manager = new PtyManager(db, config.claudeSessionsDir, push);
|
||||
const discovery = new DiscoveryService({
|
||||
ptyManager: manager,
|
||||
projectsDir: config.claudeProjectsDir,
|
||||
@@ -87,6 +91,7 @@ export function buildApp(config: Config, db: Db, serverVersion: string): AppBund
|
||||
registerSessionRoutes(app, manager, discovery);
|
||||
registerRepoRoutes(app, worktrees);
|
||||
registerWorktreeRoutes(app, worktrees);
|
||||
registerPushRoutes(app, push);
|
||||
// La route websocket doit être déclarée APRÈS le chargement du plugin (contexte
|
||||
// encapsulé) — sinon le handler reçoit la signature REST (request, reply).
|
||||
void app.register(async (scoped) => {
|
||||
@@ -105,5 +110,5 @@ export function buildApp(config: Config, db: Db, serverVersion: string): AppBund
|
||||
});
|
||||
}
|
||||
|
||||
return { app, auth, manager, discovery, worktrees };
|
||||
return { app, auth, manager, discovery, worktrees, push };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user