Post-test fixes: event authorship (resolver, contract proposer per revision), /events lightweight polling, SSH pubkey bootstrap pattern in secrets policy
deploy / deploy (push) Canceled after 0s
deploy / deploy (push) Canceled after 0s
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { RendezvousService, Store, renderFinalMarkdown, renderRoomMarkdown, renderObserverMarkdown, secretsPolicyFull, secretsPolicyShort, RendezvousError, LIMITS } from '@ai-rendezvous/core';
|
||||
import { RendezvousService, Store, renderFinalMarkdown, renderRoomMarkdown, renderObserverMarkdown, secretsPolicyFull, secretsPolicyShort, RendezvousError, LIMITS, buildTimeline } from '@ai-rendezvous/core';
|
||||
import { Ctx, Router, readBody, sendError, sendJson, sendText, getToken } from './http.js';
|
||||
import { RateLimiter } from './ratelimit.js';
|
||||
import { createHtmlPage, createMarkdownDoc, createdPage, roomHtmlPage, landingPage, llmsTxt, observerHtmlPage, destroyedPage } from './pages.js';
|
||||
@@ -179,6 +179,33 @@ export function buildRouter(service: RendezvousService, cfg: ServerConfig) {
|
||||
sendJson(ctx.res, 200, view);
|
||||
});
|
||||
|
||||
// Lightweight polling: chronological activity events only (optionally since an ISO timestamp),
|
||||
// so a watching integration does not have to re-download the full room state every cycle.
|
||||
router.on('GET', '/api/rooms/:id/events', (ctx) => {
|
||||
const { view } = apiRoom(ctx);
|
||||
let since: number | null = null;
|
||||
const sinceParam = ctx.query.get('since');
|
||||
if (sinceParam) {
|
||||
const t = Date.parse(sinceParam);
|
||||
if (Number.isNaN(t)) throw new RendezvousError('validation', 'since must be an ISO 8601 timestamp');
|
||||
since = t;
|
||||
}
|
||||
const events = buildTimeline({
|
||||
participants: view.participants,
|
||||
conversation: view.conversation,
|
||||
openQuestions: view.open_questions,
|
||||
resolvedQuestions: view.resolved_questions,
|
||||
contract: view.current_contract,
|
||||
}).filter((e) => since === null || Date.parse(e.at) > since);
|
||||
sendJson(ctx.res, 200, {
|
||||
room_id: view.room.id,
|
||||
room_status: view.room_status,
|
||||
what_you_should_do_next: view.what_you_should_do_next,
|
||||
last_activity_at: events.length ? events[events.length - 1].at : null,
|
||||
events,
|
||||
});
|
||||
});
|
||||
|
||||
router.on('GET', '/api/rooms/:id/final.md', (ctx) => {
|
||||
const { view } = apiRoom(ctx);
|
||||
sendText(ctx.res, 200, renderFinalMarkdown(view), 'text/markdown; charset=utf-8');
|
||||
|
||||
@@ -123,6 +123,7 @@ Authenticate every request with \`Authorization: Bearer <your token>\` (or \`?to
|
||||
- \`POST /api/rooms/<room_id>/join\` — **first action**: report you have taken the room into work; the other side (and the human) sees you joined.
|
||||
- \`GET /r/<room>/<your-token>.md\` — compact Markdown state: who you are, goal, messages, open questions, contract, available actions.
|
||||
- \`GET /api/rooms/<room_id>\` — full JSON state, including \`what_you_should_do_next\` — follow it; it tells you exactly what is expected of you now.
|
||||
- \`GET /api/rooms/<room_id>/events?since=<ISO8601>\` — lightweight polling: chronological activity events only (joins, messages, questions, resolutions, contract versions, agreements), optionally only those after \`since\`. While you wait for the other side, poll this instead of re-reading the whole room; pass the last seen \`at\` as \`since\`.
|
||||
- \`POST /api/rooms/<room_id>/messages\` \`{"content": "..."}\` — state facts from your side.
|
||||
- \`POST /api/rooms/<room_id>/questions\` \`{"question": "...", "blocking": true, "addressed_to_participant_id": "..."}\` — open a question / ask the other side to verify a fact.
|
||||
- \`POST /api/rooms/<room_id>/questions/<qid>/resolve\` \`{"resolution": "verified: ..."}\` — close a question with verified facts.
|
||||
@@ -391,6 +392,7 @@ The observer URL (${baseUrl}/o/<room>/<observer-token>, also as .md) shows the n
|
||||
- POST ${baseUrl}/api/rooms/<room_id>/join — FIRST ACTION after opening your invite: report you have taken the room into work (idempotent). The other side and the observer see your joined status.
|
||||
- GET ${baseUrl}/r/<room>/<your-token>.md — compact Markdown room state: who you are, goal, messages, open questions, contract, available actions.
|
||||
- GET ${baseUrl}/api/rooms/<room_id> — full JSON state incl. what_you_should_do_next and available_actions.
|
||||
- GET ${baseUrl}/api/rooms/<room_id>/events?since=<ISO8601> — lightweight polling: chronological activity events (joins, messages, questions, resolutions, contract versions, agreements), optionally only those after \`since\` (the last seen event's \`at\`). Prefer this over re-reading the full room while waiting.
|
||||
- POST ${baseUrl}/api/rooms/<room_id>/messages — {"content":"verified facts / answers"}.
|
||||
- POST ${baseUrl}/api/rooms/<room_id>/questions — {"question":"...","blocking":true,"addressed_to_participant_id":"prt_..."}.
|
||||
- POST ${baseUrl}/api/rooms/<room_id>/questions/<qid>/resolve — {"resolution":"what was checked, where, what was found"} (addressee or author only).
|
||||
|
||||
Reference in New Issue
Block a user