@ouispec/agent-realtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/dist/approvals/client-event.d.ts +4 -0
- package/dist/approvals/client-event.d.ts.map +1 -0
- package/dist/approvals/client-event.js +25 -0
- package/dist/approvals/client-event.js.map +1 -0
- package/dist/approvals/routes.d.ts +19 -0
- package/dist/approvals/routes.d.ts.map +1 -0
- package/dist/approvals/routes.js +100 -0
- package/dist/approvals/routes.js.map +1 -0
- package/dist/approvals/schemas.d.ts +7 -0
- package/dist/approvals/schemas.d.ts.map +1 -0
- package/dist/approvals/schemas.js +45 -0
- package/dist/approvals/schemas.js.map +1 -0
- package/dist/approvals/store.d.ts +33 -0
- package/dist/approvals/store.d.ts.map +1 -0
- package/dist/approvals/store.js +206 -0
- package/dist/approvals/store.js.map +1 -0
- package/dist/approvals/token.d.ts +19 -0
- package/dist/approvals/token.d.ts.map +1 -0
- package/dist/approvals/token.js +73 -0
- package/dist/approvals/token.js.map +1 -0
- package/dist/client-events/builtin.d.ts +30 -0
- package/dist/client-events/builtin.d.ts.map +1 -0
- package/dist/client-events/builtin.js +161 -0
- package/dist/client-events/builtin.js.map +1 -0
- package/dist/client-events/chain.d.ts +80 -0
- package/dist/client-events/chain.d.ts.map +1 -0
- package/dist/client-events/chain.js +92 -0
- package/dist/client-events/chain.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +85 -0
- package/dist/config.js.map +1 -0
- package/dist/events/declared.d.ts +18 -0
- package/dist/events/declared.d.ts.map +1 -0
- package/dist/events/declared.js +30 -0
- package/dist/events/declared.js.map +1 -0
- package/dist/events/settlements.d.ts +28 -0
- package/dist/events/settlements.d.ts.map +1 -0
- package/dist/events/settlements.js +29 -0
- package/dist/events/settlements.js.map +1 -0
- package/dist/http/routes.d.ts +91 -0
- package/dist/http/routes.d.ts.map +1 -0
- package/dist/http/routes.js +290 -0
- package/dist/http/routes.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +22 -0
- package/dist/logger.js.map +1 -0
- package/dist/oui/results.d.ts +46 -0
- package/dist/oui/results.d.ts.map +1 -0
- package/dist/oui/results.js +56 -0
- package/dist/oui/results.js.map +1 -0
- package/dist/redis-waits.d.ts +32 -0
- package/dist/redis-waits.d.ts.map +1 -0
- package/dist/redis-waits.js +62 -0
- package/dist/redis-waits.js.map +1 -0
- package/dist/rooms/join.d.ts +13 -0
- package/dist/rooms/join.d.ts.map +1 -0
- package/dist/rooms/join.js +27 -0
- package/dist/rooms/join.js.map +1 -0
- package/dist/rooms/room-token.d.ts +19 -0
- package/dist/rooms/room-token.d.ts.map +1 -0
- package/dist/rooms/room-token.js +55 -0
- package/dist/rooms/room-token.js.map +1 -0
- package/dist/server.d.ts +33 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +168 -0
- package/dist/server.js.map +1 -0
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +87 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/types.d.ts +135 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createPayloadValidator } from '@ouispec/agent-events/validate';
|
|
2
|
+
export function createDeclaredEvents(catalog) {
|
|
3
|
+
return { catalog, validator: createPayloadValidator(catalog) };
|
|
4
|
+
}
|
|
5
|
+
/** The rooms an event is declared for, as its patterns. */
|
|
6
|
+
function declaredRooms(events, event) {
|
|
7
|
+
return events.catalog
|
|
8
|
+
.get(event)
|
|
9
|
+
.rooms.map((r) => r.pattern ?? "the turn's room")
|
|
10
|
+
.join(', ');
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Why `data` may not be sent as `event` to `rooms`, or null when it may.
|
|
14
|
+
* `noun` names the data as the caller knows it: an emit's payload, a relay's data.
|
|
15
|
+
*/
|
|
16
|
+
export function declaredRefusal(events, event, data, rooms, noun) {
|
|
17
|
+
if (!events.catalog.has(event))
|
|
18
|
+
return `event "${event}" is not declared`;
|
|
19
|
+
if (rooms.length === 0) {
|
|
20
|
+
return `"${event}" is declared for ${declaredRooms(events, event)}; name its rooms, a declared event is never broadcast`;
|
|
21
|
+
}
|
|
22
|
+
for (const room of rooms) {
|
|
23
|
+
if (!events.catalog.allowsRoom(event, room)) {
|
|
24
|
+
return `"${event}" may not go to ${room}; it is declared for ${declaredRooms(events, event)}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const problems = events.validator.problems(event, data);
|
|
28
|
+
return problems.length > 0 ? `invalid "${event}" ${noun}: ${problems.join('; ')}` : null;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=declared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declared.js","sourceRoot":"","sources":["../../src/events/declared.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,sBAAsB,EAAyB,MAAM,gCAAgC,CAAC;AAO/F,MAAM,UAAU,oBAAoB,CAAC,OAAqB;IACxD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,2DAA2D;AAC3D,SAAS,aAAa,CAAC,MAAsB,EAAE,KAAa;IAC1D,OAAO,MAAM,CAAC,OAAO;SAClB,GAAG,CAAC,KAAK,CAAE;SACX,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,iBAAiB,CAAC;SAChD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAsB,EACtB,KAAa,EACb,IAAa,EACb,KAAwB,EACxB,IAAwB;IAExB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,UAAU,KAAK,mBAAmB,CAAC;IAC1E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,KAAK,qBAAqB,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,uDAAuD,CAAC;IAC3H,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YAC5C,OAAO,IAAI,KAAK,mBAAmB,IAAI,wBAAwB,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QAChG,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACxD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job settlements, kept for the workers that wait on them (W9).
|
|
3
|
+
*
|
|
4
|
+
* Every declared completion or failure the server emits settles one job: the
|
|
5
|
+
* job of its kind whose id is in its correlation field. The first is kept, so
|
|
6
|
+
* a worker on any instance can ask how the job ended without joining a room,
|
|
7
|
+
* even when it asks after the event went out:
|
|
8
|
+
*
|
|
9
|
+
* events:settlement:{kind}:{id} → JSON Settlement, TTL 35 min, first wins
|
|
10
|
+
* channel events:settlements → `{kind}:{id}`, published when one is kept
|
|
11
|
+
*
|
|
12
|
+
* The emitter is the product's backend, trusted by the internal key; so is
|
|
13
|
+
* the worker that reads. No browser reaches either.
|
|
14
|
+
*/
|
|
15
|
+
import type { Settlement } from '@ouispec/agent-events';
|
|
16
|
+
import type { RealtimeLogger } from '../logger.js';
|
|
17
|
+
import { type ResultsRedis, type ResultsSubscriber } from '../redis-waits.js';
|
|
18
|
+
/** As long as the longest wait on a job may run, with margin: the same horizon as a final UI action result. */
|
|
19
|
+
export declare const SETTLEMENT_TTL_SEC: number;
|
|
20
|
+
export interface SettlementStore {
|
|
21
|
+
/** Keep a job's settlement. Returns false when the job was already settled. */
|
|
22
|
+
record(settlement: Settlement): Promise<boolean>;
|
|
23
|
+
/** The job's settlement, waiting up to `waitMs` for it. */
|
|
24
|
+
await(kind: string, id: string, waitMs: number): Promise<Settlement | null>;
|
|
25
|
+
pendingCount(): number;
|
|
26
|
+
}
|
|
27
|
+
export declare function createSettlementStore(redis: ResultsRedis, subscriber: ResultsSubscriber, logger: RealtimeLogger): SettlementStore;
|
|
28
|
+
//# sourceMappingURL=settlements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlements.d.ts","sourceRoot":"","sources":["../../src/events/settlements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAiB,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG7F,+GAA+G;AAC/G,eAAO,MAAM,kBAAkB,QAAU,CAAC;AAK1C,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,2DAA2D;IAC3D,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC5E,YAAY,IAAI,MAAM,CAAC;CACxB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,EAAE,cAAc,GAAG,eAAe,CAoCjI"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createWaitHub } from '../redis-waits.js';
|
|
2
|
+
const CHANNEL = 'events:settlements';
|
|
3
|
+
/** As long as the longest wait on a job may run, with margin: the same horizon as a final UI action result. */
|
|
4
|
+
export const SETTLEMENT_TTL_SEC = 35 * 60;
|
|
5
|
+
const settlementId = (kind, id) => `${kind}:${id}`;
|
|
6
|
+
const settlementKey = (kind, id) => `events:settlement:${settlementId(kind, id)}`;
|
|
7
|
+
export function createSettlementStore(redis, subscriber, logger) {
|
|
8
|
+
const hub = createWaitHub(subscriber, CHANNEL, logger, 'Settlements');
|
|
9
|
+
async function read(kind, id) {
|
|
10
|
+
const raw = await redis.get(settlementKey(kind, id));
|
|
11
|
+
return raw ? JSON.parse(raw) : null;
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
async record(settlement) {
|
|
15
|
+
const written = await redis.set(settlementKey(settlement.kind, settlement.id), JSON.stringify(settlement), 'EX', SETTLEMENT_TTL_SEC, 'NX');
|
|
16
|
+
if (written !== 'OK') {
|
|
17
|
+
logger.info({ kind: settlement.kind, id: settlement.id, event: settlement.event }, 'Job already settled; later settlement not kept');
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
await redis.publish(CHANNEL, settlementId(settlement.kind, settlement.id));
|
|
21
|
+
return true;
|
|
22
|
+
},
|
|
23
|
+
await(kind, id, waitMs) {
|
|
24
|
+
return hub.wait(settlementId(kind, id), waitMs, () => read(kind, id), (err) => logger.error({ err, kind, id }, 'Settlement read failed'));
|
|
25
|
+
},
|
|
26
|
+
pendingCount: () => hub.pendingCount(),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=settlements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlements.js","sourceRoot":"","sources":["../../src/events/settlements.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,aAAa,EAA6C,MAAM,mBAAmB,CAAC;AAE7F,MAAM,OAAO,GAAG,oBAAoB,CAAC;AACrC,+GAA+G;AAC/G,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,CAAC;AAE1C,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;AACnE,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,EAAE,CAAC,qBAAqB,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;AAUlG,MAAM,UAAU,qBAAqB,CAAC,KAAmB,EAAE,UAA6B,EAAE,MAAsB;IAC9G,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAEtE,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,EAAU;QAC1C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QACrD,OAAO,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,CAAC;IAED,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,UAAU;YACrB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,GAAG,CAC7B,aAAa,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,EAC7C,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAC1B,IAAI,EACJ,kBAAkB,EAClB,IAAI,CACL,CAAC;YACF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,EACrE,gDAAgD,CACjD,CAAC;gBACF,OAAO,KAAK,CAAC;YACf,CAAC;YACD,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3E,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM;YACpB,OAAO,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAC5E,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,wBAAwB,CAAC,CAC1D,CAAC;QACJ,CAAC;QAED,YAAY,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,YAAY,EAAE;KACvC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import type { Server } from 'socket.io';
|
|
3
|
+
import type { RoomPolicy } from '../types.js';
|
|
4
|
+
import type { RoomTokenSigner } from '../rooms/room-token.js';
|
|
5
|
+
import type { OUIResultStore } from '../oui/results.js';
|
|
6
|
+
import type { RealtimeLogger } from '../logger.js';
|
|
7
|
+
import { type DeclaredEvents } from '../events/declared.js';
|
|
8
|
+
import type { SettlementStore } from '../events/settlements.js';
|
|
9
|
+
/** The longest a single result wait may hold a request open. Callers ask again until their own deadline. */
|
|
10
|
+
export declare const MAX_RESULT_WAIT_MS = 25000;
|
|
11
|
+
/** The longest `/api/emit` waits for the receivers' receipts (`ackTimeoutMs`). */
|
|
12
|
+
export declare const MAX_RECEIPT_WAIT_MS = 5000;
|
|
13
|
+
/** What `/api/emit` reports when asked for receipts: how many receivers acknowledged, and how many accepted. */
|
|
14
|
+
export interface EmitReceipts {
|
|
15
|
+
acknowledged: number;
|
|
16
|
+
accepted: number;
|
|
17
|
+
}
|
|
18
|
+
/** A constant-time check of the internal key. */
|
|
19
|
+
export declare function createInternalKeyCheck(internalApiKey: string): (presented: string | undefined) => boolean;
|
|
20
|
+
export interface RouteDeps {
|
|
21
|
+
io: Server;
|
|
22
|
+
roomPolicy: RoomPolicy;
|
|
23
|
+
roomTokens: RoomTokenSigner;
|
|
24
|
+
/** Null until Redis is connected. */
|
|
25
|
+
results: () => OUIResultStore | null;
|
|
26
|
+
/** The product's event declarations; null when none were given. */
|
|
27
|
+
declared: DeclaredEvents | null;
|
|
28
|
+
/** Null when there are no declarations. */
|
|
29
|
+
settlements: () => SettlementStore | null;
|
|
30
|
+
isInternalKey: (presented: string | undefined) => boolean;
|
|
31
|
+
logger: RealtimeLogger;
|
|
32
|
+
}
|
|
33
|
+
export declare function healthRouter(deps: Pick<RouteDeps, 'io' | 'results'>): Router;
|
|
34
|
+
/**
|
|
35
|
+
* POST /api/emit — `{ event, data, rooms? }`. Sends a server event to rooms,
|
|
36
|
+
* or to every socket when `rooms` is empty or absent. How the product's
|
|
37
|
+
* backend and worker reach clients (turn events, UI action dispatches, job
|
|
38
|
+
* events).
|
|
39
|
+
*
|
|
40
|
+
* With event declarations: only a declared event, with a payload its schema
|
|
41
|
+
* accepts, into rooms it is declared for (never a broadcast); anything else is
|
|
42
|
+
* a 400, logged. A completion or failure is then kept as its job's settlement.
|
|
43
|
+
*
|
|
44
|
+
* With `ackTimeoutMs` (rooms only, at most MAX_RECEIPT_WAIT_MS): the event asks
|
|
45
|
+
* its receivers for a receipt, and the response says how many acknowledged it
|
|
46
|
+
* within that time and how many accepted it (`receipts`). A UI action request
|
|
47
|
+
* is answered `{ ok: true }` by a tab that received it (oui-spec §7.3.7), so the
|
|
48
|
+
* worker can tell a request that reached the page from one that reached
|
|
49
|
+
* nobody, and send it again only then.
|
|
50
|
+
*/
|
|
51
|
+
export declare function emitRouter(deps: RouteDeps): Router;
|
|
52
|
+
/**
|
|
53
|
+
* POST /internal/room-token — `{ userId, room }` → `{ token }`.
|
|
54
|
+
*
|
|
55
|
+
* Signs a token that admits `userId` to `room`, for any room the policy marks
|
|
56
|
+
* `requiresToken`. The product calls it only after its own authorization for
|
|
57
|
+
* the resource accepted the user; this route decides nothing about access.
|
|
58
|
+
*/
|
|
59
|
+
export declare function roomTokenRouter(deps: RouteDeps): Router;
|
|
60
|
+
/**
|
|
61
|
+
* GET /internal/oui/action-results/:requestId?userId=&waitMs=&final=1
|
|
62
|
+
*
|
|
63
|
+
* The client's answer to a UI action request (ADR-0209). Waits up to `waitMs`
|
|
64
|
+
* (capped at 25 s) for it to arrive. With `final=1`, the final answer: for an
|
|
65
|
+
* async action, the one sent when its work is done or has failed, never its
|
|
66
|
+
* acknowledgment; for any other action, its one answer.
|
|
67
|
+
* 200 — the OUIActionResult
|
|
68
|
+
* 204 — no answer yet; ask again
|
|
69
|
+
* 400 — userId missing or waitMs invalid
|
|
70
|
+
* 401 — missing or wrong internal API key
|
|
71
|
+
* 503 — the result store is not connected
|
|
72
|
+
*
|
|
73
|
+
* `userId` is the user the turn belongs to. An answer from any other user's
|
|
74
|
+
* socket is never returned.
|
|
75
|
+
*/
|
|
76
|
+
export declare function ouiResultsRouter(deps: RouteDeps): Router;
|
|
77
|
+
/**
|
|
78
|
+
* GET /internal/events/settlements/:kind/:id?waitMs=
|
|
79
|
+
*
|
|
80
|
+
* How a job of a declared kind ended: its first completion or failure, as
|
|
81
|
+
* `{ kind, role, event, id, payload }`. Waits up to `waitMs` (capped at 25 s)
|
|
82
|
+
* for it; a worker asks again until its own deadline.
|
|
83
|
+
* 200 — the settlement
|
|
84
|
+
* 204 — not settled yet
|
|
85
|
+
* 400 — an undeclared kind, or waitMs invalid
|
|
86
|
+
* 401 — missing or wrong internal API key
|
|
87
|
+
* 404 — this server has no event declarations
|
|
88
|
+
* 503 — the store is not connected
|
|
89
|
+
*/
|
|
90
|
+
export declare function settlementsRouter(deps: RouteDeps): Router;
|
|
91
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/http/routes.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,4GAA4G;AAC5G,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,OAAQ,CAAC;AAEzC,gHAAgH;AAChH,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,iDAAiD;AACjD,wBAAgB,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAMzG;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,eAAe,CAAC;IAC5B,qCAAqC;IACrC,OAAO,EAAE,MAAM,cAAc,GAAG,IAAI,CAAC;IACrC,mEAAmE;IACnE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,2CAA2C;IAC3C,WAAW,EAAE,MAAM,eAAe,GAAG,IAAI,CAAC;IAC1C,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;IAC1D,MAAM,EAAE,cAAc,CAAC;CACxB;AAQD,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,CAc5E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAyElD;AAqBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CA2BvD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAoCxD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAsCzD"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server's HTTP endpoints. Every `/internal/*` and `/api/emit` route
|
|
3
|
+
* requires the internal key (`x-api-key`); they are for the product's backend
|
|
4
|
+
* and its agent worker, never a browser.
|
|
5
|
+
*/
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
import { Router } from 'express';
|
|
8
|
+
import { declaredRefusal } from '../events/declared.js';
|
|
9
|
+
/** The longest a single result wait may hold a request open. Callers ask again until their own deadline. */
|
|
10
|
+
export const MAX_RESULT_WAIT_MS = 25_000;
|
|
11
|
+
/** The longest `/api/emit` waits for the receivers' receipts (`ackTimeoutMs`). */
|
|
12
|
+
export const MAX_RECEIPT_WAIT_MS = 5_000;
|
|
13
|
+
/** A constant-time check of the internal key. */
|
|
14
|
+
export function createInternalKeyCheck(internalApiKey) {
|
|
15
|
+
const expected = crypto.createHash('sha256').update(internalApiKey).digest();
|
|
16
|
+
return (presented) => {
|
|
17
|
+
if (typeof presented !== 'string' || presented.length === 0)
|
|
18
|
+
return false;
|
|
19
|
+
return crypto.timingSafeEqual(crypto.createHash('sha256').update(presented).digest(), expected);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function refuseWithoutKey(deps, req, res) {
|
|
23
|
+
if (deps.isInternalKey(req.headers['x-api-key']))
|
|
24
|
+
return false;
|
|
25
|
+
res.status(401).json({ error: 'Invalid or missing API key' });
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
export function healthRouter(deps) {
|
|
29
|
+
const router = Router();
|
|
30
|
+
const startedAt = Date.now();
|
|
31
|
+
router.get('/health', (_req, res) => {
|
|
32
|
+
const results = deps.results();
|
|
33
|
+
res.status(results ? 200 : 503).json({
|
|
34
|
+
status: results ? 'ok' : 'starting',
|
|
35
|
+
uptime: Math.floor((Date.now() - startedAt) / 1000),
|
|
36
|
+
connections: deps.io.engine.clientsCount,
|
|
37
|
+
pendingResultWaits: results?.pendingCount() ?? 0,
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
return router;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* POST /api/emit — `{ event, data, rooms? }`. Sends a server event to rooms,
|
|
45
|
+
* or to every socket when `rooms` is empty or absent. How the product's
|
|
46
|
+
* backend and worker reach clients (turn events, UI action dispatches, job
|
|
47
|
+
* events).
|
|
48
|
+
*
|
|
49
|
+
* With event declarations: only a declared event, with a payload its schema
|
|
50
|
+
* accepts, into rooms it is declared for (never a broadcast); anything else is
|
|
51
|
+
* a 400, logged. A completion or failure is then kept as its job's settlement.
|
|
52
|
+
*
|
|
53
|
+
* With `ackTimeoutMs` (rooms only, at most MAX_RECEIPT_WAIT_MS): the event asks
|
|
54
|
+
* its receivers for a receipt, and the response says how many acknowledged it
|
|
55
|
+
* within that time and how many accepted it (`receipts`). A UI action request
|
|
56
|
+
* is answered `{ ok: true }` by a tab that received it (oui-spec §7.3.7), so the
|
|
57
|
+
* worker can tell a request that reached the page from one that reached
|
|
58
|
+
* nobody, and send it again only then.
|
|
59
|
+
*/
|
|
60
|
+
export function emitRouter(deps) {
|
|
61
|
+
const router = Router();
|
|
62
|
+
router.post('/api/emit', async (req, res) => {
|
|
63
|
+
if (refuseWithoutKey(deps, req, res))
|
|
64
|
+
return;
|
|
65
|
+
const { event, data, rooms, ackTimeoutMs } = (req.body ?? {});
|
|
66
|
+
if (!event || typeof event !== 'string') {
|
|
67
|
+
res.status(400).json({ error: 'event is required and must be a string' });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (rooms !== undefined && (!Array.isArray(rooms) || rooms.some((r) => typeof r !== 'string'))) {
|
|
71
|
+
res.status(400).json({ error: 'rooms must be an array of strings' });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (ackTimeoutMs !== undefined &&
|
|
75
|
+
(typeof ackTimeoutMs !== 'number' ||
|
|
76
|
+
!Number.isInteger(ackTimeoutMs) ||
|
|
77
|
+
ackTimeoutMs < 1 ||
|
|
78
|
+
ackTimeoutMs > MAX_RECEIPT_WAIT_MS)) {
|
|
79
|
+
res.status(400).json({ error: `ackTimeoutMs must be a whole number of ms from 1 to ${MAX_RECEIPT_WAIT_MS}` });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const targets = rooms ?? [];
|
|
83
|
+
if (ackTimeoutMs !== undefined && targets.length === 0) {
|
|
84
|
+
res.status(400).json({ error: 'receipts (ackTimeoutMs) are asked of rooms, never of a broadcast' });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const invalid = targets.filter((r) => !deps.roomPolicy.isValidRoom(r));
|
|
88
|
+
if (invalid.length > 0) {
|
|
89
|
+
res.status(400).json({ error: `Invalid room names: ${invalid.join(', ')}` });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (deps.declared) {
|
|
93
|
+
const reason = declaredRefusal(deps.declared, event, data, targets, 'payload');
|
|
94
|
+
if (reason) {
|
|
95
|
+
deps.logger.warn({ event, rooms: targets, reason }, 'Emit refused');
|
|
96
|
+
res.status(400).json({ error: reason });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
let receipts = null;
|
|
101
|
+
if (targets.length > 0 && ackTimeoutMs !== undefined) {
|
|
102
|
+
receipts = await emitWithReceipts(deps.io, targets, event, data, ackTimeoutMs);
|
|
103
|
+
deps.logger.info({ event, rooms: targets, hasData: data != null, receipts }, 'Emitted to rooms');
|
|
104
|
+
}
|
|
105
|
+
else if (targets.length > 0) {
|
|
106
|
+
deps.io.to(targets).emit(event, data);
|
|
107
|
+
deps.logger.info({ event, rooms: targets, hasData: data != null }, 'Emitted to rooms');
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
deps.io.emit(event, data);
|
|
111
|
+
deps.logger.info({ event, hasData: data != null }, 'Broadcast emitted');
|
|
112
|
+
}
|
|
113
|
+
const settlement = deps.declared?.catalog.settlement(event, data) ?? null;
|
|
114
|
+
const store = deps.settlements();
|
|
115
|
+
if (settlement && store) {
|
|
116
|
+
try {
|
|
117
|
+
await store.record(settlement);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
// The event reached its rooms; only a worker's later wait on the job misses it.
|
|
121
|
+
deps.logger.error({ err, event, kind: settlement.kind, id: settlement.id }, 'Settlement not kept');
|
|
122
|
+
res.json({ ok: true, settled: false, ...(receipts ? { receipts } : {}) });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
res.json({ ok: true, ...(receipts ? { receipts } : {}) });
|
|
127
|
+
});
|
|
128
|
+
return router;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Emit to rooms asking each receiver for an acknowledgment, and count them:
|
|
132
|
+
* those that answered within `timeoutMs`, and of those, the ones that accepted
|
|
133
|
+
* (anything but `{ ok: false }`). A receiver that does not acknowledge — an
|
|
134
|
+
* older client — counts in neither, so its sender falls back to its own
|
|
135
|
+
* schedule. Across instances through the Redis adapter's broadcast acks.
|
|
136
|
+
*/
|
|
137
|
+
function emitWithReceipts(io, rooms, event, data, timeoutMs) {
|
|
138
|
+
return new Promise((resolve) => {
|
|
139
|
+
io.to(rooms)
|
|
140
|
+
.timeout(timeoutMs)
|
|
141
|
+
.emit(event, data, (_err, responses = []) => {
|
|
142
|
+
const acks = Array.isArray(responses) ? responses : [];
|
|
143
|
+
const accepted = acks.filter((r) => !(r && typeof r === 'object' && r.ok === false)).length;
|
|
144
|
+
resolve({ acknowledged: acks.length, accepted });
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* POST /internal/room-token — `{ userId, room }` → `{ token }`.
|
|
150
|
+
*
|
|
151
|
+
* Signs a token that admits `userId` to `room`, for any room the policy marks
|
|
152
|
+
* `requiresToken`. The product calls it only after its own authorization for
|
|
153
|
+
* the resource accepted the user; this route decides nothing about access.
|
|
154
|
+
*/
|
|
155
|
+
export function roomTokenRouter(deps) {
|
|
156
|
+
const router = Router();
|
|
157
|
+
router.post('/internal/room-token', (req, res) => {
|
|
158
|
+
if (refuseWithoutKey(deps, req, res))
|
|
159
|
+
return;
|
|
160
|
+
const { userId, room } = (req.body ?? {});
|
|
161
|
+
if (!userId || typeof userId !== 'string') {
|
|
162
|
+
res.status(400).json({ error: 'userId is required and must be a string' });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!room || typeof room !== 'string') {
|
|
166
|
+
res.status(400).json({ error: 'room is required and must be a string' });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (!deps.roomPolicy.isValidRoom(room)) {
|
|
170
|
+
res.status(400).json({ error: `Invalid room name: ${room}` });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (!deps.roomPolicy.requiresToken(room)) {
|
|
174
|
+
res.status(400).json({ error: `${room} is joined by identity, not with a room token` });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const token = deps.roomTokens.sign(userId, room);
|
|
178
|
+
deps.logger.info({ userId, room }, 'Room token issued');
|
|
179
|
+
res.json({ token, expiresInMs: deps.roomTokens.ttlMs });
|
|
180
|
+
});
|
|
181
|
+
return router;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* GET /internal/oui/action-results/:requestId?userId=&waitMs=&final=1
|
|
185
|
+
*
|
|
186
|
+
* The client's answer to a UI action request (ADR-0209). Waits up to `waitMs`
|
|
187
|
+
* (capped at 25 s) for it to arrive. With `final=1`, the final answer: for an
|
|
188
|
+
* async action, the one sent when its work is done or has failed, never its
|
|
189
|
+
* acknowledgment; for any other action, its one answer.
|
|
190
|
+
* 200 — the OUIActionResult
|
|
191
|
+
* 204 — no answer yet; ask again
|
|
192
|
+
* 400 — userId missing or waitMs invalid
|
|
193
|
+
* 401 — missing or wrong internal API key
|
|
194
|
+
* 503 — the result store is not connected
|
|
195
|
+
*
|
|
196
|
+
* `userId` is the user the turn belongs to. An answer from any other user's
|
|
197
|
+
* socket is never returned.
|
|
198
|
+
*/
|
|
199
|
+
export function ouiResultsRouter(deps) {
|
|
200
|
+
const router = Router();
|
|
201
|
+
router.get('/internal/oui/action-results/:requestId', async (req, res) => {
|
|
202
|
+
if (refuseWithoutKey(deps, req, res))
|
|
203
|
+
return;
|
|
204
|
+
const requestId = req.params.requestId;
|
|
205
|
+
const userId = typeof req.query.userId === 'string' ? req.query.userId : '';
|
|
206
|
+
const waitMs = req.query.waitMs === undefined ? 0 : Number(req.query.waitMs);
|
|
207
|
+
const final = req.query.final === '1' || req.query.final === 'true';
|
|
208
|
+
if (!userId) {
|
|
209
|
+
res.status(400).json({ error: 'userId is required' });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
213
|
+
res.status(400).json({ error: 'waitMs must be a non-negative number' });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const store = deps.results();
|
|
217
|
+
if (!store) {
|
|
218
|
+
res.status(503).json({ error: 'OUI result store not connected' });
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const result = await store.await(requestId, userId, Math.min(waitMs, MAX_RESULT_WAIT_MS), { final });
|
|
223
|
+
if (!result) {
|
|
224
|
+
res.status(204).end();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
res.json(result);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
deps.logger.error({ err, requestId, userId }, 'OUI result lookup failed');
|
|
231
|
+
res.status(500).json({ error: 'OUI result lookup failed' });
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
return router;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* GET /internal/events/settlements/:kind/:id?waitMs=
|
|
238
|
+
*
|
|
239
|
+
* How a job of a declared kind ended: its first completion or failure, as
|
|
240
|
+
* `{ kind, role, event, id, payload }`. Waits up to `waitMs` (capped at 25 s)
|
|
241
|
+
* for it; a worker asks again until its own deadline.
|
|
242
|
+
* 200 — the settlement
|
|
243
|
+
* 204 — not settled yet
|
|
244
|
+
* 400 — an undeclared kind, or waitMs invalid
|
|
245
|
+
* 401 — missing or wrong internal API key
|
|
246
|
+
* 404 — this server has no event declarations
|
|
247
|
+
* 503 — the store is not connected
|
|
248
|
+
*/
|
|
249
|
+
export function settlementsRouter(deps) {
|
|
250
|
+
const router = Router();
|
|
251
|
+
router.get('/internal/events/settlements/:kind/:id', async (req, res) => {
|
|
252
|
+
if (refuseWithoutKey(deps, req, res))
|
|
253
|
+
return;
|
|
254
|
+
if (!deps.declared) {
|
|
255
|
+
res.status(404).json({ error: 'this server has no event declarations' });
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const kind = req.params.kind;
|
|
259
|
+
const id = req.params.id;
|
|
260
|
+
const waitMs = req.query.waitMs === undefined ? 0 : Number(req.query.waitMs);
|
|
261
|
+
if (!deps.declared.catalog.jobKind(kind)) {
|
|
262
|
+
const declared = deps.declared.catalog.jobKinds().map((k) => k.kind);
|
|
263
|
+
res.status(400).json({ error: `job kind '${kind}' is not declared (declared: ${declared.join(', ') || 'none'})` });
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
267
|
+
res.status(400).json({ error: 'waitMs must be a non-negative number' });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const store = deps.settlements();
|
|
271
|
+
if (!store) {
|
|
272
|
+
res.status(503).json({ error: 'settlement store not connected' });
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
const settlement = await store.await(kind, id, Math.min(waitMs, MAX_RESULT_WAIT_MS));
|
|
277
|
+
if (!settlement) {
|
|
278
|
+
res.status(204).end();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
res.json(settlement);
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
deps.logger.error({ err, kind, id }, 'Settlement lookup failed');
|
|
285
|
+
res.status(500).json({ error: 'settlement lookup failed' });
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
return router;
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/http/routes.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ouispec/agent-realtime — the realtime server for agent turns and
|
|
3
|
+
* UI actions.
|
|
4
|
+
*
|
|
5
|
+
* The product supplies: an auth verifier, a room policy, the internal key, the
|
|
6
|
+
* room-token secret, the approval signing key, Redis and its CORS origins,
|
|
7
|
+
* and optionally its event declarations (ADR-0227 §2.2).
|
|
8
|
+
* The server handles: declared client events, room tokens, the UI action
|
|
9
|
+
* result store, the approval store, the emit API (held to the declarations),
|
|
10
|
+
* job settlements, and fan-out across instances.
|
|
11
|
+
*/
|
|
12
|
+
export type { RealtimeServerConfig, AuthAdapter, AuthResult, RoomPolicy, RelayRule, PayloadSchema, RedisConfig, RoomTokenConfig, ApprovalsConfig, } from './types.js';
|
|
13
|
+
export { createRealtimeServer } from './server.js';
|
|
14
|
+
export type { RealtimeServerInstance } from './server.js';
|
|
15
|
+
export { assertRealtimeServerConfig } from './config.js';
|
|
16
|
+
export { defineClientEvent, registerClientEvents } from './client-events/chain.js';
|
|
17
|
+
export type { ClientEvent, ClientEventDefinition, ClientEventContext, Authorization, AuthenticatedSocket, } from './client-events/chain.js';
|
|
18
|
+
export { relayRefusal } from './client-events/builtin.js';
|
|
19
|
+
export { createRoomTokenSigner, DEFAULT_ROOM_TOKEN_TTL_MS } from './rooms/room-token.js';
|
|
20
|
+
export type { RoomTokenSigner, RoomTokenPayload } from './rooms/room-token.js';
|
|
21
|
+
export { joinRefusal } from './rooms/join.js';
|
|
22
|
+
export { createOUIResultStore, RESULT_TTL_SEC, FINAL_RESULT_TTL_SEC } from './oui/results.js';
|
|
23
|
+
export type { OUIResultStore } from './oui/results.js';
|
|
24
|
+
export type { ResultsRedis, ResultsSubscriber } from './redis-waits.js';
|
|
25
|
+
export { createSettlementStore, SETTLEMENT_TTL_SEC } from './events/settlements.js';
|
|
26
|
+
export type { SettlementStore } from './events/settlements.js';
|
|
27
|
+
export { MAX_RESULT_WAIT_MS } from './http/routes.js';
|
|
28
|
+
export { createConsoleLogger } from './logger.js';
|
|
29
|
+
export type { RealtimeLogger } from './logger.js';
|
|
30
|
+
export { createApprovalStore, DECLINED_TTL_SEC } from './approvals/store.js';
|
|
31
|
+
export type { ApprovalStore, ApprovalRedis } from './approvals/store.js';
|
|
32
|
+
export { createApprovalTokenSigner, MIN_APPROVAL_KEY_LENGTH } from './approvals/token.js';
|
|
33
|
+
export type { ApprovalTokenSigner, ApprovalTokenCheck } from './approvals/token.js';
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,WAAW,EACX,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACnF,YAAY,EACV,WAAW,EACX,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC9F,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACpF,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC1F,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ouispec/agent-realtime — the realtime server for agent turns and
|
|
3
|
+
* UI actions.
|
|
4
|
+
*
|
|
5
|
+
* The product supplies: an auth verifier, a room policy, the internal key, the
|
|
6
|
+
* room-token secret, the approval signing key, Redis and its CORS origins,
|
|
7
|
+
* and optionally its event declarations (ADR-0227 §2.2).
|
|
8
|
+
* The server handles: declared client events, room tokens, the UI action
|
|
9
|
+
* result store, the approval store, the emit API (held to the declarations),
|
|
10
|
+
* job settlements, and fan-out across instances.
|
|
11
|
+
*/
|
|
12
|
+
export { createRealtimeServer } from './server.js';
|
|
13
|
+
export { assertRealtimeServerConfig } from './config.js';
|
|
14
|
+
export { defineClientEvent, registerClientEvents } from './client-events/chain.js';
|
|
15
|
+
export { relayRefusal } from './client-events/builtin.js';
|
|
16
|
+
export { createRoomTokenSigner, DEFAULT_ROOM_TOKEN_TTL_MS } from './rooms/room-token.js';
|
|
17
|
+
export { joinRefusal } from './rooms/join.js';
|
|
18
|
+
export { createOUIResultStore, RESULT_TTL_SEC, FINAL_RESULT_TTL_SEC } from './oui/results.js';
|
|
19
|
+
export { createSettlementStore, SETTLEMENT_TTL_SEC } from './events/settlements.js';
|
|
20
|
+
export { MAX_RESULT_WAIT_MS } from './http/routes.js';
|
|
21
|
+
export { createConsoleLogger } from './logger.js';
|
|
22
|
+
export { createApprovalStore, DECLINED_TTL_SEC } from './approvals/store.js';
|
|
23
|
+
export { createApprovalTokenSigner, MIN_APPROVAL_KEY_LENGTH } from './approvals/token.js';
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAaH,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAQnF,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAEzF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAG9F,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server logs refusals, joins and results as structured records. pino's
|
|
3
|
+
* `(object, message)` signature is the shape, so a product passes its own
|
|
4
|
+
* pino logger unchanged.
|
|
5
|
+
*/
|
|
6
|
+
export interface RealtimeLogger {
|
|
7
|
+
debug(data: Record<string, unknown>, msg: string): void;
|
|
8
|
+
info(data: Record<string, unknown>, msg: string): void;
|
|
9
|
+
warn(data: Record<string, unknown>, msg: string): void;
|
|
10
|
+
error(data: Record<string, unknown>, msg: string): void;
|
|
11
|
+
}
|
|
12
|
+
/** One JSON line per record. Debug records are written only when `LOG_LEVEL=debug`. */
|
|
13
|
+
export declare function createConsoleLogger(): RealtimeLogger;
|
|
14
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxD,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACvD,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACvD,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACzD;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,IAAI,cAAc,CAWpD"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** One JSON line per record. Debug records are written only when `LOG_LEVEL=debug`. */
|
|
2
|
+
export function createConsoleLogger() {
|
|
3
|
+
const line = (level, data, msg) => JSON.stringify({ level, time: Date.now(), msg, ...serializable(data) });
|
|
4
|
+
return {
|
|
5
|
+
debug: (data, msg) => {
|
|
6
|
+
if (process.env.LOG_LEVEL === 'debug')
|
|
7
|
+
console.log(line('debug', data, msg));
|
|
8
|
+
},
|
|
9
|
+
info: (data, msg) => console.log(line('info', data, msg)),
|
|
10
|
+
warn: (data, msg) => console.warn(line('warn', data, msg)),
|
|
11
|
+
error: (data, msg) => console.error(line('error', data, msg)),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Errors serialize to `{}` in JSON; keep their message and stack. */
|
|
15
|
+
function serializable(data) {
|
|
16
|
+
const out = {};
|
|
17
|
+
for (const [key, value] of Object.entries(data)) {
|
|
18
|
+
out[key] = value instanceof Error ? { message: value.message, stack: value.stack } : value;
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAYA,uFAAuF;AACvF,MAAM,UAAU,mBAAmB;IACjC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,IAA6B,EAAE,GAAW,EAAE,EAAE,CACzE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1E,OAAO;QACL,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;YACnB,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,OAAO;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACzD,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAC1D,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,SAAS,YAAY,CAAC,IAA6B;IACjD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|