@opengeni/events 0.3.36 → 0.3.52
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/dist/coalesce.d.ts +4 -0
- package/dist/index.d.ts +37 -148
- package/dist/nats-jwt.d.ts +103 -0
- package/package.json +5 -5
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type SessionEvent } from "@opengeni/contracts";
|
|
2
|
+
/** Flush long runs incrementally before concatenation can become unbounded. */
|
|
3
|
+
export declare const SESSION_EVENT_COALESCED_TEXT_TARGET_BYTES: number;
|
|
4
|
+
export declare function coalesceSessionEventDeltas(events: SessionEvent[]): SessionEvent[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,144 +1,35 @@
|
|
|
1
|
-
import { SessionEvent, WorkspaceControlEvent } from
|
|
2
|
-
import { appendSessionEvents,
|
|
3
|
-
import { connect } from
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
/** Flush long runs incrementally before concatenation can become unbounded. */
|
|
7
|
-
declare const SESSION_EVENT_COALESCED_TEXT_TARGET_BYTES: number;
|
|
8
|
-
declare function coalesceSessionEventDeltas(events: SessionEvent[]): SessionEvent[];
|
|
9
|
-
|
|
10
|
-
/** A NATS permission set: subject allow/deny lists (ADR-26 `pub`/`sub` →
|
|
11
|
-
* `allow`/`deny`). An empty/undefined list means "no explicit grant" — combined
|
|
12
|
-
* with the agent scope below, the connection can ONLY reach what `allow` lists. */
|
|
13
|
-
interface NatsPermission {
|
|
14
|
-
allow?: string[];
|
|
15
|
-
deny?: string[];
|
|
16
|
-
}
|
|
17
|
-
/** The pub/sub permissions embedded in a user JWT. */
|
|
18
|
-
interface NatsPermissions {
|
|
19
|
-
pub: NatsPermission;
|
|
20
|
-
sub: NatsPermission;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Input to mint a workspace-scoped NATS user JWT for an enrolled agent.
|
|
24
|
-
* - `userPublicKey` — the `user_nkey` from the authorization request; it MUST be
|
|
25
|
-
* the `sub` of the user JWT (nats-server rejects a mismatch).
|
|
26
|
-
* - `accountSeed` — the callout account SIGNING seed (`SA...`); both the user JWT
|
|
27
|
-
* `iss` (its public key) and the signature come from it. NEVER logged.
|
|
28
|
-
* - `name` — a human label for the user (the agent id), for server logs.
|
|
29
|
-
* - `permissions` — the pub/sub allow/deny lists (the workspace scope).
|
|
30
|
-
* - `expiresAtSeconds` — optional absolute `exp` (unix seconds). When set the
|
|
31
|
-
* server will expire the connection's credential; we tie it to the bearer's
|
|
32
|
-
* remaining life so a revoked/expired enrollment cannot outlive its bearer.
|
|
33
|
-
*/
|
|
34
|
-
interface MintUserJwtInput {
|
|
35
|
-
userPublicKey: string;
|
|
36
|
-
accountSeed: string;
|
|
37
|
-
name: string;
|
|
38
|
-
permissions: NatsPermissions;
|
|
39
|
-
/** The target account NAME (the `auth_callout.account`) the user binds to; the
|
|
40
|
-
* embedded user JWT's `aud` in server-config mode. */
|
|
41
|
-
audienceAccount: string;
|
|
42
|
-
expiresAtSeconds?: number;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Mint a signed NATS user JWT scoped by `permissions`. In auth-callout SERVER
|
|
46
|
-
* mode the user JWT is signed by the callout ISSUER ACCOUNT key, and its `iss` is
|
|
47
|
-
* that account's public key. The returned JWT is embedded as `nats.jwt` in the
|
|
48
|
-
* authorization response.
|
|
49
|
-
*/
|
|
50
|
-
declare function mintUserJwt(input: MintUserJwtInput): string;
|
|
51
|
-
/**
|
|
52
|
-
* Input to mint the authorization RESPONSE JWT the responder publishes back on the
|
|
53
|
-
* request's reply subject (ADR-26 §3).
|
|
54
|
-
* - `userPublicKey` — the request's `user_nkey`; the response `sub`.
|
|
55
|
-
* - `serverId` — the request's `nats.server_id.id` (the server's public key); the
|
|
56
|
-
* response `aud`.
|
|
57
|
-
* - `accountSeed` — the callout account signing seed; signs the response and is
|
|
58
|
-
* its `iss` (public key). NEVER logged.
|
|
59
|
-
* - `userJwt` — the embedded signed user JWT (omit on a denial).
|
|
60
|
-
* - `error` — a human-readable denial message (omit on success). When present the
|
|
61
|
-
* server denies the connection.
|
|
62
|
-
*/
|
|
63
|
-
interface MintAuthResponseInput {
|
|
64
|
-
userPublicKey: string;
|
|
65
|
-
serverId: string;
|
|
66
|
-
accountSeed: string;
|
|
67
|
-
userJwt?: string;
|
|
68
|
-
error?: string;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Mint the signed authorization-response JWT. On success it carries the embedded
|
|
72
|
-
* user JWT (`nats.jwt`); on denial it carries `nats.error` and NO user JWT, which
|
|
73
|
-
* makes nats-server refuse the connection. Signed by the callout account key (its
|
|
74
|
-
* public key is `iss`); `sub` is the user_nkey, `aud` is the server id.
|
|
75
|
-
*/
|
|
76
|
-
declare function mintAuthResponse(input: MintAuthResponseInput): string;
|
|
77
|
-
/**
|
|
78
|
-
* The fields the responder needs out of the authorization REQUEST JWT (ADR-26 §2).
|
|
79
|
-
* The request is itself a NATS JWT (`header.payload.signature`) the server signs;
|
|
80
|
-
* we only DECODE it (the server proves its own identity by the connection, and the
|
|
81
|
-
* embedded `auth_token` is independently HMAC-verified), so we read the payload
|
|
82
|
-
* without re-verifying the server signature.
|
|
83
|
-
*/
|
|
84
|
-
interface DecodedAuthRequest {
|
|
85
|
-
/** The public user nkey the response user JWT MUST be `sub`-scoped to. */
|
|
86
|
-
userNkey: string;
|
|
87
|
-
/** The server's public id — the response `aud`. */
|
|
88
|
-
serverId: string;
|
|
89
|
-
/** The connect `auth_token` the client presented (our `oge_` bearer), if any. */
|
|
90
|
-
authToken: string | undefined;
|
|
91
|
-
/** The connect username, if any (unused today; present for completeness). */
|
|
92
|
-
user: string | undefined;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Decode the authorization-request JWT payload (the middle base64url segment). The
|
|
96
|
-
* request shape (ADR-26 §2): `nats.user_nkey`, `nats.server_id.id`, and the
|
|
97
|
-
* presented connect options under `nats.connect_opts` (`auth_token` / `user`).
|
|
98
|
-
* Returns null on a malformed token so the caller can deny cleanly.
|
|
99
|
-
*/
|
|
100
|
-
declare function decodeAuthRequest(token: string): DecodedAuthRequest | null;
|
|
101
|
-
/**
|
|
102
|
-
* Build the workspace-scoped permission set for an agent: it may publish + subscribe
|
|
103
|
-
* ONLY `agent.<workspaceId>.>` (its own RPC/event/hello subtree) and the reply
|
|
104
|
-
* `_INBOX.>` subtree (so request/reply round-trips work). Everything else is
|
|
105
|
-
* implicitly denied (an allow-list with no other entries IS the deny-all-else).
|
|
106
|
-
*
|
|
107
|
-
* THE isolation assertion (§17): with `workspaceId=A`, the returned allow lists name
|
|
108
|
-
* only `agent.A.>` — so a connection bearing this credential is rejected by
|
|
109
|
-
* nats-server the instant it tries to pub/sub `agent.B.>`. This is the per-workspace
|
|
110
|
-
* tenancy boundary, enforced cryptographically by the signed JWT, not by naming.
|
|
111
|
-
*/
|
|
112
|
-
declare function workspaceAgentPermissions(workspaceId: string): NatsPermissions;
|
|
113
|
-
|
|
114
|
-
type EventLogger = {
|
|
1
|
+
import { type SessionEvent, type WorkspaceControlEvent } from "@opengeni/contracts";
|
|
2
|
+
import { appendSessionEvents, type AppendEventInput, type Database } from "@opengeni/db";
|
|
3
|
+
import { connect } from "nats";
|
|
4
|
+
export type EventLogger = {
|
|
115
5
|
debug?: (message: string, attributes?: Record<string, unknown>) => void;
|
|
116
6
|
warn?: (message: string, attributes?: Record<string, unknown>) => void;
|
|
117
7
|
};
|
|
118
|
-
type EventBusOptions = {
|
|
8
|
+
export type EventBusOptions = {
|
|
119
9
|
logger?: EventLogger;
|
|
120
10
|
/** Test/host transport seam; production defaults to the nats.js connector. */
|
|
121
11
|
connect?: typeof connect;
|
|
122
12
|
};
|
|
123
|
-
|
|
13
|
+
export { SESSION_EVENT_COALESCED_TEXT_TARGET_BYTES, coalesceSessionEventDeltas } from "./coalesce";
|
|
124
14
|
/** Comfortably below NATS Core's common 1 MiB max_payload default. */
|
|
125
|
-
declare const SESSION_EVENT_NATS_MESSAGE_MAX_BYTES: number;
|
|
15
|
+
export declare const SESSION_EVENT_NATS_MESSAGE_MAX_BYTES: number;
|
|
126
16
|
/** Payload is <=64 KiB; the larger envelope leaves deterministic wire headroom. */
|
|
127
|
-
declare const SESSION_EVENT_SSE_FRAME_MAX_BYTES: number;
|
|
17
|
+
export declare const SESSION_EVENT_SSE_FRAME_MAX_BYTES: number;
|
|
128
18
|
/** Independent count+byte envelope for one durable HTTP replay response. */
|
|
129
|
-
declare const SESSION_EVENT_HTTP_PAGE_MAX_BYTES: number;
|
|
19
|
+
export declare const SESSION_EVENT_HTTP_PAGE_MAX_BYTES: number;
|
|
130
20
|
/** Workspace invalidations are one compact event, never a broker evidence blob. */
|
|
131
|
-
declare const WORKSPACE_CONTROL_NATS_MESSAGE_MAX_BYTES: number;
|
|
21
|
+
export declare const WORKSPACE_CONTROL_NATS_MESSAGE_MAX_BYTES: number;
|
|
132
22
|
/** Count+byte envelope for one workspace-control REST replay page. */
|
|
133
|
-
declare const WORKSPACE_CONTROL_HTTP_PAGE_MAX_BYTES: number;
|
|
134
|
-
|
|
23
|
+
export declare const WORKSPACE_CONTROL_HTTP_PAGE_MAX_BYTES: number;
|
|
24
|
+
export { decodeAuthRequest, mintAuthResponse, mintUserJwt, workspaceAgentPermissions, type DecodedAuthRequest, type MintAuthResponseInput, type MintUserJwtInput, type NatsPermission, type NatsPermissions, } from "./nats-jwt";
|
|
25
|
+
export { connect, nkeys, type NatsConnection } from "nats";
|
|
135
26
|
/**
|
|
136
27
|
* A raw request/reply reply — just the response bytes. Mirrors the subset of the
|
|
137
28
|
* NATS `Msg` shape a binary request/reply caller needs (`NatsControlRpc` consumes
|
|
138
29
|
* exactly this). Kept minimal so the events package does not leak the `nats` `Msg`
|
|
139
30
|
* type into the agent-loop-free runtime leaf.
|
|
140
31
|
*/
|
|
141
|
-
type RequestReply = {
|
|
32
|
+
export type RequestReply = {
|
|
142
33
|
data: Uint8Array;
|
|
143
34
|
};
|
|
144
35
|
/**
|
|
@@ -149,7 +40,7 @@ type RequestReply = {
|
|
|
149
40
|
* natively supports both pub/sub and request/reply, so there is NEVER a second
|
|
150
41
|
* connection.
|
|
151
42
|
*/
|
|
152
|
-
interface RequestConnection {
|
|
43
|
+
export interface RequestConnection {
|
|
153
44
|
request(subject: string, payload: Uint8Array, opts: {
|
|
154
45
|
timeout: number;
|
|
155
46
|
}): Promise<RequestReply>;
|
|
@@ -162,7 +53,7 @@ interface RequestConnection {
|
|
|
162
53
|
* (`agent.<ws>.<id>.ack`). Same managed connection as everything else — a NATS
|
|
163
54
|
* connection natively supports all of it; there is NEVER a second connection.
|
|
164
55
|
*/
|
|
165
|
-
interface OpStreamConnection {
|
|
56
|
+
export interface OpStreamConnection {
|
|
166
57
|
subscribe(subject: string): AsyncIterable<{
|
|
167
58
|
data: Uint8Array;
|
|
168
59
|
}> & {
|
|
@@ -177,8 +68,8 @@ interface OpStreamConnection {
|
|
|
177
68
|
* leaves the request unanswered (the caller's request times out / sees no
|
|
178
69
|
* responder), which the control plane maps to `agent_offline` / reconnecting.
|
|
179
70
|
*/
|
|
180
|
-
type RequestHandler = (request: Uint8Array, subject: string) => Promise<Uint8Array> | Uint8Array;
|
|
181
|
-
type EventBus = {
|
|
71
|
+
export type RequestHandler = (request: Uint8Array, subject: string) => Promise<Uint8Array> | Uint8Array;
|
|
72
|
+
export type EventBus = {
|
|
182
73
|
publish: (workspaceId: string, sessionId: string, events: SessionEvent[]) => Promise<void>;
|
|
183
74
|
subscribe: (workspaceId: string, sessionId: string, onEvents: (events: SessionEvent[]) => void | Promise<void>) => Promise<() => void>;
|
|
184
75
|
/** Best-effort live invalidation; the event is already durable in Postgres. */
|
|
@@ -235,7 +126,7 @@ type EventBus = {
|
|
|
235
126
|
* is omitted the connection is anonymous (local dev / a NATS without auth_callout)
|
|
236
127
|
* — the existing behavior, unchanged.
|
|
237
128
|
*/
|
|
238
|
-
declare function createNatsEventBus(natsUrl: string, auth?: {
|
|
129
|
+
export declare function createNatsEventBus(natsUrl: string, auth?: {
|
|
239
130
|
user: string;
|
|
240
131
|
pass: string;
|
|
241
132
|
}, options?: EventBusOptions): Promise<EventBus>;
|
|
@@ -252,12 +143,12 @@ declare function createNatsEventBus(natsUrl: string, auth?: {
|
|
|
252
143
|
* server publishes an authorization request with a reply inbox; the handler returns
|
|
253
144
|
* the signed authorization-response bytes which we `respond` on that inbox.
|
|
254
145
|
*/
|
|
255
|
-
interface ResponderConnection {
|
|
146
|
+
export interface ResponderConnection {
|
|
256
147
|
/** Subscribe-and-reply on `subject`; returns an async close that drains. */
|
|
257
148
|
close: () => Promise<void>;
|
|
258
149
|
}
|
|
259
150
|
/** Connection auth for a standalone NATS connection (the callout responder). */
|
|
260
|
-
type NatsConnectAuth = {
|
|
151
|
+
export type NatsConnectAuth = {
|
|
261
152
|
kind: "user-password";
|
|
262
153
|
user: string;
|
|
263
154
|
pass: string;
|
|
@@ -276,7 +167,7 @@ type NatsConnectAuth = {
|
|
|
276
167
|
* connection on its own timeout, which is the correct fail-closed behavior (a
|
|
277
168
|
* responder bug must never accidentally grant access).
|
|
278
169
|
*/
|
|
279
|
-
declare function createResponderConnection(natsUrl: string, auth: NatsConnectAuth, subject: string, handler: RequestHandler, options?: {
|
|
170
|
+
export declare function createResponderConnection(natsUrl: string, auth: NatsConnectAuth, subject: string, handler: RequestHandler, options?: {
|
|
280
171
|
name?: string;
|
|
281
172
|
logger?: EventLogger;
|
|
282
173
|
connect?: typeof connect;
|
|
@@ -288,7 +179,7 @@ declare function createResponderConnection(natsUrl: string, auth: NatsConnectAut
|
|
|
288
179
|
* Kept as a plain callback so the events package takes no dependency on the
|
|
289
180
|
* observability package; the worker wires it to Prometheus histograms.
|
|
290
181
|
*/
|
|
291
|
-
type AppendPublishObserver = {
|
|
182
|
+
export type AppendPublishObserver = {
|
|
292
183
|
onAppend?: (info: {
|
|
293
184
|
durationSeconds: number;
|
|
294
185
|
count: number;
|
|
@@ -298,7 +189,7 @@ type AppendPublishObserver = {
|
|
|
298
189
|
count: number;
|
|
299
190
|
}) => void;
|
|
300
191
|
};
|
|
301
|
-
type AppendPublishOptions = AppendPublishObserver & {
|
|
192
|
+
export type AppendPublishOptions = AppendPublishObserver & {
|
|
302
193
|
/** Test/host persistence seam; production uses the database implementation. */
|
|
303
194
|
appendSessionEvents?: typeof appendSessionEvents;
|
|
304
195
|
};
|
|
@@ -310,40 +201,40 @@ type AppendPublishOptions = AppendPublishObserver & {
|
|
|
310
201
|
* `appendAndPublishEvents` (spreading the real module for everything else), so the
|
|
311
202
|
* observer wiring can only be exercised through a helper that survives that mock.
|
|
312
203
|
*/
|
|
313
|
-
declare function observeSince(fn: ((info: {
|
|
204
|
+
export declare function observeSince(fn: ((info: {
|
|
314
205
|
durationSeconds: number;
|
|
315
206
|
count: number;
|
|
316
207
|
}) => void) | undefined, startedAt: number, count: number): void;
|
|
317
|
-
declare function appendAndPublishEvents(db: Database, bus: EventBus, workspaceId: string, sessionId: string, events: AppendEventInput[], options?: AppendPublishOptions): Promise<SessionEvent[]>;
|
|
208
|
+
export declare function appendAndPublishEvents(db: Database, bus: EventBus, workspaceId: string, sessionId: string, events: AppendEventInput[], options?: AppendPublishOptions): Promise<SessionEvent[]>;
|
|
318
209
|
/**
|
|
319
210
|
* Best-effort live fanout for events another DB helper already committed in
|
|
320
211
|
* the same transaction as related durable state. This must never append again.
|
|
321
212
|
*/
|
|
322
|
-
declare function publishDurableSessionEvents(bus: EventBus, workspaceId: string, sessionId: string, appended: SessionEvent[], observe?: AppendPublishObserver): Promise<void>;
|
|
213
|
+
export declare function publishDurableSessionEvents(bus: EventBus, workspaceId: string, sessionId: string, appended: SessionEvent[], observe?: AppendPublishObserver): Promise<void>;
|
|
323
214
|
/** Best-effort fanout for a workspace-control event already committed in PostgreSQL. */
|
|
324
|
-
declare function publishDurableWorkspaceControlEvent(bus: EventBus, workspaceId: string, event: WorkspaceControlEvent): Promise<void>;
|
|
325
|
-
declare function appendAndPublishTurnEventsFenced(db: Database, bus: EventBus, workspaceId: string, sessionId: string, turnId: string, executionGeneration: number, attemptId: string, events: AppendEventInput[]): Promise<{
|
|
215
|
+
export declare function publishDurableWorkspaceControlEvent(bus: EventBus, workspaceId: string, event: WorkspaceControlEvent): Promise<void>;
|
|
216
|
+
export declare function appendAndPublishTurnEventsFenced(db: Database, bus: EventBus, workspaceId: string, sessionId: string, turnId: string, executionGeneration: number, attemptId: string, events: AppendEventInput[]): Promise<{
|
|
326
217
|
events: SessionEvent[];
|
|
327
218
|
accepted: boolean;
|
|
328
219
|
}>;
|
|
329
|
-
declare function formatSse<T extends {
|
|
220
|
+
export declare function formatSse<T extends {
|
|
330
221
|
sequence: number;
|
|
331
222
|
type: string;
|
|
332
223
|
}>(event: T): string;
|
|
333
224
|
/** Canonical one-event NATS payload with an exact broker byte assertion. */
|
|
334
|
-
declare function workspaceControlEventNatsPayload(event: WorkspaceControlEvent): Uint8Array;
|
|
225
|
+
export declare function workspaceControlEventNatsPayload(event: WorkspaceControlEvent): Uint8Array;
|
|
335
226
|
/** Defensively bounds current and historical workspace invalidations per frame. */
|
|
336
|
-
declare function formatWorkspaceControlEventSse(event: WorkspaceControlEvent): string;
|
|
227
|
+
export declare function formatWorkspaceControlEventSse(event: WorkspaceControlEvent): string;
|
|
337
228
|
/** Defensively bounds historical rows before they become one SSE frame. */
|
|
338
|
-
declare function formatSessionEventSse(event: SessionEvent): string;
|
|
229
|
+
export declare function formatSessionEventSse(event: SessionEvent): string;
|
|
339
230
|
/**
|
|
340
231
|
* Split an already-durable batch by exact encoded NATS bytes. Each event is
|
|
341
232
|
* defensively normalized first so historical oversized rows cannot exceed the
|
|
342
233
|
* broker envelope. Sequence and ordering are unchanged across chunks.
|
|
343
234
|
*/
|
|
344
|
-
declare function sessionEventBatchesByBytes(workspaceId: string, sessionId: string, events: readonly SessionEvent[], maxBytes?: number): SessionEvent[][];
|
|
235
|
+
export declare function sessionEventBatchesByBytes(workspaceId: string, sessionId: string, events: readonly SessionEvent[], maxBytes?: number): SessionEvent[][];
|
|
345
236
|
/** Return one count+byte-bounded HTTP page and truthful continuation facts. */
|
|
346
|
-
declare function boundSessionEventHttpPage(events: readonly SessionEvent[], options: {
|
|
237
|
+
export declare function boundSessionEventHttpPage(events: readonly SessionEvent[], options: {
|
|
347
238
|
direction: "after" | "before";
|
|
348
239
|
maxBytes?: number;
|
|
349
240
|
}): {
|
|
@@ -353,13 +244,11 @@ declare function boundSessionEventHttpPage(events: readonly SessionEvent[], opti
|
|
|
353
244
|
bytes: number;
|
|
354
245
|
};
|
|
355
246
|
/** Return one count+byte-bounded workspace-control page and resume cursor. */
|
|
356
|
-
declare function boundWorkspaceControlHttpPage(events: readonly WorkspaceControlEvent[], maxBytes?: number): {
|
|
247
|
+
export declare function boundWorkspaceControlHttpPage(events: readonly WorkspaceControlEvent[], maxBytes?: number): {
|
|
357
248
|
events: WorkspaceControlEvent[];
|
|
358
249
|
truncated: boolean;
|
|
359
250
|
nextSequence: number | null;
|
|
360
251
|
bytes: number;
|
|
361
252
|
};
|
|
362
253
|
/** Raw durable cursor covered by a possibly coalesced compact event. */
|
|
363
|
-
declare function sessionEventResumeSequence(event: SessionEvent): number;
|
|
364
|
-
|
|
365
|
-
export { type AppendPublishObserver, type AppendPublishOptions, type DecodedAuthRequest, type EventBus, type EventBusOptions, type EventLogger, type MintAuthResponseInput, type MintUserJwtInput, type NatsConnectAuth, type NatsPermission, type NatsPermissions, type OpStreamConnection, type RequestConnection, type RequestHandler, type RequestReply, type ResponderConnection, SESSION_EVENT_COALESCED_TEXT_TARGET_BYTES, SESSION_EVENT_HTTP_PAGE_MAX_BYTES, SESSION_EVENT_NATS_MESSAGE_MAX_BYTES, SESSION_EVENT_SSE_FRAME_MAX_BYTES, WORKSPACE_CONTROL_HTTP_PAGE_MAX_BYTES, WORKSPACE_CONTROL_NATS_MESSAGE_MAX_BYTES, appendAndPublishEvents, appendAndPublishTurnEventsFenced, boundSessionEventHttpPage, boundWorkspaceControlHttpPage, coalesceSessionEventDeltas, createNatsEventBus, createResponderConnection, decodeAuthRequest, formatSessionEventSse, formatSse, formatWorkspaceControlEventSse, mintAuthResponse, mintUserJwt, observeSince, publishDurableSessionEvents, publishDurableWorkspaceControlEvent, sessionEventBatchesByBytes, sessionEventResumeSequence, workspaceAgentPermissions, workspaceControlEventNatsPayload };
|
|
254
|
+
export declare function sessionEventResumeSequence(event: SessionEvent): number;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** A NATS permission set: subject allow/deny lists (ADR-26 `pub`/`sub` →
|
|
2
|
+
* `allow`/`deny`). An empty/undefined list means "no explicit grant" — combined
|
|
3
|
+
* with the agent scope below, the connection can ONLY reach what `allow` lists. */
|
|
4
|
+
export interface NatsPermission {
|
|
5
|
+
allow?: string[];
|
|
6
|
+
deny?: string[];
|
|
7
|
+
}
|
|
8
|
+
/** The pub/sub permissions embedded in a user JWT. */
|
|
9
|
+
export interface NatsPermissions {
|
|
10
|
+
pub: NatsPermission;
|
|
11
|
+
sub: NatsPermission;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Input to mint a workspace-scoped NATS user JWT for an enrolled agent.
|
|
15
|
+
* - `userPublicKey` — the `user_nkey` from the authorization request; it MUST be
|
|
16
|
+
* the `sub` of the user JWT (nats-server rejects a mismatch).
|
|
17
|
+
* - `accountSeed` — the callout account SIGNING seed (`SA...`); both the user JWT
|
|
18
|
+
* `iss` (its public key) and the signature come from it. NEVER logged.
|
|
19
|
+
* - `name` — a human label for the user (the agent id), for server logs.
|
|
20
|
+
* - `permissions` — the pub/sub allow/deny lists (the workspace scope).
|
|
21
|
+
* - `expiresAtSeconds` — optional absolute `exp` (unix seconds). When set the
|
|
22
|
+
* server will expire the connection's credential; we tie it to the bearer's
|
|
23
|
+
* remaining life so a revoked/expired enrollment cannot outlive its bearer.
|
|
24
|
+
*/
|
|
25
|
+
export interface MintUserJwtInput {
|
|
26
|
+
userPublicKey: string;
|
|
27
|
+
accountSeed: string;
|
|
28
|
+
name: string;
|
|
29
|
+
permissions: NatsPermissions;
|
|
30
|
+
/** The target account NAME (the `auth_callout.account`) the user binds to; the
|
|
31
|
+
* embedded user JWT's `aud` in server-config mode. */
|
|
32
|
+
audienceAccount: string;
|
|
33
|
+
expiresAtSeconds?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Mint a signed NATS user JWT scoped by `permissions`. In auth-callout SERVER
|
|
37
|
+
* mode the user JWT is signed by the callout ISSUER ACCOUNT key, and its `iss` is
|
|
38
|
+
* that account's public key. The returned JWT is embedded as `nats.jwt` in the
|
|
39
|
+
* authorization response.
|
|
40
|
+
*/
|
|
41
|
+
export declare function mintUserJwt(input: MintUserJwtInput): string;
|
|
42
|
+
/**
|
|
43
|
+
* Input to mint the authorization RESPONSE JWT the responder publishes back on the
|
|
44
|
+
* request's reply subject (ADR-26 §3).
|
|
45
|
+
* - `userPublicKey` — the request's `user_nkey`; the response `sub`.
|
|
46
|
+
* - `serverId` — the request's `nats.server_id.id` (the server's public key); the
|
|
47
|
+
* response `aud`.
|
|
48
|
+
* - `accountSeed` — the callout account signing seed; signs the response and is
|
|
49
|
+
* its `iss` (public key). NEVER logged.
|
|
50
|
+
* - `userJwt` — the embedded signed user JWT (omit on a denial).
|
|
51
|
+
* - `error` — a human-readable denial message (omit on success). When present the
|
|
52
|
+
* server denies the connection.
|
|
53
|
+
*/
|
|
54
|
+
export interface MintAuthResponseInput {
|
|
55
|
+
userPublicKey: string;
|
|
56
|
+
serverId: string;
|
|
57
|
+
accountSeed: string;
|
|
58
|
+
userJwt?: string;
|
|
59
|
+
error?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Mint the signed authorization-response JWT. On success it carries the embedded
|
|
63
|
+
* user JWT (`nats.jwt`); on denial it carries `nats.error` and NO user JWT, which
|
|
64
|
+
* makes nats-server refuse the connection. Signed by the callout account key (its
|
|
65
|
+
* public key is `iss`); `sub` is the user_nkey, `aud` is the server id.
|
|
66
|
+
*/
|
|
67
|
+
export declare function mintAuthResponse(input: MintAuthResponseInput): string;
|
|
68
|
+
/**
|
|
69
|
+
* The fields the responder needs out of the authorization REQUEST JWT (ADR-26 §2).
|
|
70
|
+
* The request is itself a NATS JWT (`header.payload.signature`) the server signs;
|
|
71
|
+
* we only DECODE it (the server proves its own identity by the connection, and the
|
|
72
|
+
* embedded `auth_token` is independently HMAC-verified), so we read the payload
|
|
73
|
+
* without re-verifying the server signature.
|
|
74
|
+
*/
|
|
75
|
+
export interface DecodedAuthRequest {
|
|
76
|
+
/** The public user nkey the response user JWT MUST be `sub`-scoped to. */
|
|
77
|
+
userNkey: string;
|
|
78
|
+
/** The server's public id — the response `aud`. */
|
|
79
|
+
serverId: string;
|
|
80
|
+
/** The connect `auth_token` the client presented (our `oge_` bearer), if any. */
|
|
81
|
+
authToken: string | undefined;
|
|
82
|
+
/** The connect username, if any (unused today; present for completeness). */
|
|
83
|
+
user: string | undefined;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Decode the authorization-request JWT payload (the middle base64url segment). The
|
|
87
|
+
* request shape (ADR-26 §2): `nats.user_nkey`, `nats.server_id.id`, and the
|
|
88
|
+
* presented connect options under `nats.connect_opts` (`auth_token` / `user`).
|
|
89
|
+
* Returns null on a malformed token so the caller can deny cleanly.
|
|
90
|
+
*/
|
|
91
|
+
export declare function decodeAuthRequest(token: string): DecodedAuthRequest | null;
|
|
92
|
+
/**
|
|
93
|
+
* Build the workspace-scoped permission set for an agent: it may publish + subscribe
|
|
94
|
+
* ONLY `agent.<workspaceId>.>` (its own RPC/event/hello subtree) and the reply
|
|
95
|
+
* `_INBOX.>` subtree (so request/reply round-trips work). Everything else is
|
|
96
|
+
* implicitly denied (an allow-list with no other entries IS the deny-all-else).
|
|
97
|
+
*
|
|
98
|
+
* THE isolation assertion (§17): with `workspaceId=A`, the returned allow lists name
|
|
99
|
+
* only `agent.A.>` — so a connection bearing this credential is rejected by
|
|
100
|
+
* nats-server the instant it tries to pub/sub `agent.B.>`. This is the per-workspace
|
|
101
|
+
* tenancy boundary, enforced cryptographically by the signed JWT, not by naming.
|
|
102
|
+
*/
|
|
103
|
+
export declare function workspaceAgentPermissions(workspaceId: string): NatsPermissions;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/events",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.52",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"provenance": true
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
|
-
"build": "
|
|
30
|
-
"typecheck": "
|
|
29
|
+
"build": "bun ../../scripts/build-typescript-package.ts",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
31
|
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@opengeni/contracts": "^0.
|
|
35
|
-
"@opengeni/db": "^0.
|
|
34
|
+
"@opengeni/contracts": "^0.27.0",
|
|
35
|
+
"@opengeni/db": "^0.17.1",
|
|
36
36
|
"nats": "^2.29.3"
|
|
37
37
|
}
|
|
38
38
|
}
|