dsh-a2a-server 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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +335 -0
  3. package/README.zh-CN.md +316 -0
  4. package/cordis.patch.yml +30 -0
  5. package/lib/config.d.ts +116 -0
  6. package/lib/config.d.ts.map +1 -0
  7. package/lib/config.js +110 -0
  8. package/lib/config.js.map +1 -0
  9. package/lib/contexts.d.ts +84 -0
  10. package/lib/contexts.d.ts.map +1 -0
  11. package/lib/contexts.js +103 -0
  12. package/lib/contexts.js.map +1 -0
  13. package/lib/index.d.ts +33 -0
  14. package/lib/index.d.ts.map +1 -0
  15. package/lib/index.js +505 -0
  16. package/lib/index.js.map +1 -0
  17. package/lib/projection.d.ts +131 -0
  18. package/lib/projection.d.ts.map +1 -0
  19. package/lib/projection.js +98 -0
  20. package/lib/projection.js.map +1 -0
  21. package/lib/protocol/brand.d.ts +32 -0
  22. package/lib/protocol/brand.d.ts.map +1 -0
  23. package/lib/protocol/brand.js +25 -0
  24. package/lib/protocol/brand.js.map +1 -0
  25. package/lib/protocol/card.d.ts +43 -0
  26. package/lib/protocol/card.d.ts.map +1 -0
  27. package/lib/protocol/card.js +58 -0
  28. package/lib/protocol/card.js.map +1 -0
  29. package/lib/protocol/index.d.ts +23 -0
  30. package/lib/protocol/index.d.ts.map +1 -0
  31. package/lib/protocol/index.js +20 -0
  32. package/lib/protocol/index.js.map +1 -0
  33. package/lib/protocol/jsonrpc.d.ts +93 -0
  34. package/lib/protocol/jsonrpc.d.ts.map +1 -0
  35. package/lib/protocol/jsonrpc.js +81 -0
  36. package/lib/protocol/jsonrpc.js.map +1 -0
  37. package/lib/protocol/normalize.d.ts +72 -0
  38. package/lib/protocol/normalize.d.ts.map +1 -0
  39. package/lib/protocol/normalize.js +278 -0
  40. package/lib/protocol/normalize.js.map +1 -0
  41. package/lib/protocol/sse.d.ts +20 -0
  42. package/lib/protocol/sse.d.ts.map +1 -0
  43. package/lib/protocol/sse.js +23 -0
  44. package/lib/protocol/sse.js.map +1 -0
  45. package/lib/protocol/wire.d.ts +164 -0
  46. package/lib/protocol/wire.d.ts.map +1 -0
  47. package/lib/protocol/wire.js +26 -0
  48. package/lib/protocol/wire.js.map +1 -0
  49. package/lib/router.d.ts +56 -0
  50. package/lib/router.d.ts.map +1 -0
  51. package/lib/router.js +432 -0
  52. package/lib/router.js.map +1 -0
  53. package/lib/security.d.ts +89 -0
  54. package/lib/security.d.ts.map +1 -0
  55. package/lib/security.js +171 -0
  56. package/lib/security.js.map +1 -0
  57. package/lib/tasks.d.ts +75 -0
  58. package/lib/tasks.d.ts.map +1 -0
  59. package/lib/tasks.js +84 -0
  60. package/lib/tasks.js.map +1 -0
  61. package/lib/types.d.ts +71 -0
  62. package/lib/types.d.ts.map +1 -0
  63. package/lib/types.js +17 -0
  64. package/lib/types.js.map +1 -0
  65. package/package.json +94 -0
package/lib/router.js ADDED
@@ -0,0 +1,432 @@
1
+ /**
2
+ * HTTP + JSON-RPC dispatch.
3
+ *
4
+ * Deliberately free of Cordis: everything it needs arrives through
5
+ * {@link RouterDeps}, so the RPC semantics can be unit-tested without booting a
6
+ * composition or opening a socket. This is the same separation Hermes reached
7
+ * for when it made its request handler reachable through `server.adapter`.
8
+ *
9
+ * @module dsh-a2a/router
10
+ */
11
+ import { A2AContextId, ERR_INVALID_PARAMS, ERR_INVALID_REQUEST, ERR_METHOD_NOT_FOUND, ERR_PARSE, ERR_PUSH_NOT_SUPPORTED, ERR_TASK_NOT_CANCELABLE, ERR_UNSUPPORTED_OPERATION, A2ARpcError, jsonRpcError, jsonRpcResult, nowIso, parseSendParams, partsToText, renderStatusUpdate, renderTask, resolveMethod, sseFrame, taskNotFound, } from "./protocol/index.js";
12
+ import { filterInbound, redactOutbound } from "./security.js";
13
+ /** Largest request body accepted, before parsing. */
14
+ const MAX_BODY_BYTES = 1_000_000;
15
+ /**
16
+ * Build the router.
17
+ * @param deps - the injected plugin capabilities.
18
+ * @returns the route handlers plus stream teardown.
19
+ */
20
+ export function createRouter(deps) {
21
+ const { config } = deps;
22
+ const streams = new Set();
23
+ const sendJson = (res, status, body) => {
24
+ const text = JSON.stringify(body);
25
+ res.writeHead(status, {
26
+ 'content-type': 'application/json',
27
+ 'content-length': Buffer.byteLength(text),
28
+ });
29
+ res.end(text);
30
+ };
31
+ /**
32
+ * Answer an authentication-class failure.
33
+ *
34
+ * The status carries the real meaning — A2A puts transport security at the
35
+ * HTTP layer — while the body stays a valid JSON-RPC error envelope so a
36
+ * client that only parses bodies is not left with nothing.
37
+ */
38
+ const sendAuthFailure = (res, status, message) => {
39
+ if (status === 401)
40
+ res.setHeader('www-authenticate', 'Bearer');
41
+ sendJson(res, status, jsonRpcError(null, ERR_INVALID_REQUEST, message));
42
+ };
43
+ const readBody = async (req) => {
44
+ const chunks = [];
45
+ let size = 0;
46
+ for await (const chunk of req) {
47
+ const buffer = chunk;
48
+ size += buffer.length;
49
+ if (size > MAX_BODY_BYTES)
50
+ throw new A2ARpcError(ERR_PARSE, 'payload too large', 413);
51
+ chunks.push(buffer);
52
+ }
53
+ return Buffer.concat(chunks).toString('utf8');
54
+ };
55
+ const serveCard = (req, res) => {
56
+ // The card is public by design: discovery requires an anonymous read. A
57
+ // deployment that serves only known internal peers may still close it.
58
+ if (!config.card.public) {
59
+ sendAuthFailure(res, 401, 'unauthorized');
60
+ return;
61
+ }
62
+ sendJson(res, 200, deps.cardFor(req.headers.host));
63
+ };
64
+ const serveRpc = async (req, res) => {
65
+ if (req.method !== 'POST') {
66
+ sendJson(res, 405, jsonRpcError(null, ERR_INVALID_REQUEST, 'method not allowed'));
67
+ return;
68
+ }
69
+ let peer;
70
+ try {
71
+ deps.assertOpen();
72
+ const secrets = await deps.resolvePeerSecrets();
73
+ const header = req.headers.authorization;
74
+ peer = deps.identify(typeof header === 'string' ? /^Bearer\s+(.+)$/i.exec(header.trim())?.[1] : undefined, secrets);
75
+ }
76
+ catch (error) {
77
+ sendJson(res, 503, jsonRpcError(null, ERR_INVALID_REQUEST, String(error)));
78
+ return;
79
+ }
80
+ if (peer === undefined) {
81
+ sendAuthFailure(res, 401, 'unauthorized');
82
+ return;
83
+ }
84
+ if (!deps.rateLimiter.allow(peer)) {
85
+ sendAuthFailure(res, 429, 'rate limit exceeded');
86
+ return;
87
+ }
88
+ // An EMPTY allow list means "no allow list", matching the documented
89
+ // "omit to allow every authenticated peer". Schemastery materializes an
90
+ // omitted array as `[]`, so testing only for `undefined` would silently
91
+ // lock out every peer on a config that never mentioned trustedPeers.
92
+ if (config.trustedPeers !== undefined && config.trustedPeers.length > 0
93
+ && !config.trustedPeers.includes(peer)) {
94
+ sendAuthFailure(res, 403, `peer "${peer}" is not trusted`);
95
+ return;
96
+ }
97
+ let body;
98
+ try {
99
+ body = await readBody(req);
100
+ }
101
+ catch (error) {
102
+ const rpc = error;
103
+ sendJson(res, rpc.httpStatus ?? 400, jsonRpcError(null, rpc.code ?? ERR_PARSE, rpc.message));
104
+ return;
105
+ }
106
+ let request;
107
+ try {
108
+ const parsed = JSON.parse(body.length === 0 ? '{}' : body);
109
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
110
+ sendJson(res, 400, jsonRpcError(null, ERR_INVALID_REQUEST, 'request must be a JSON object'));
111
+ return;
112
+ }
113
+ request = parsed;
114
+ }
115
+ catch {
116
+ sendJson(res, 400, jsonRpcError(null, ERR_PARSE, 'parse error'));
117
+ return;
118
+ }
119
+ const id = (request['id'] ?? null);
120
+ const method = typeof request['method'] === 'string' ? request['method'] : '';
121
+ const params = request['params'];
122
+ if (params !== undefined && (params === null || typeof params !== 'object')) {
123
+ sendJson(res, 200, jsonRpcError(id, ERR_INVALID_PARAMS, 'params must be an object'));
124
+ return;
125
+ }
126
+ const version = req.headers['a2a-version'];
127
+ if (typeof version === 'string' && version.length > 0
128
+ && !['0.3', '0.3.0', '1.0', '1.0.0'].includes(version)) {
129
+ sendJson(res, 200, jsonRpcError(id, ERR_INVALID_PARAMS, `unsupported A2A-Version: ${version}`));
130
+ return;
131
+ }
132
+ const entry = resolveMethod(method);
133
+ if (entry === undefined) {
134
+ sendJson(res, 200, jsonRpcError(id, ERR_METHOD_NOT_FOUND, `method not found: ${method}`));
135
+ return;
136
+ }
137
+ try {
138
+ await dispatch(entry.operation, entry.dialect, id, params, peer, res);
139
+ }
140
+ catch (error) {
141
+ if (error instanceof A2ARpcError) {
142
+ sendJson(res, error.httpStatus, jsonRpcError(id, error.code, error.message));
143
+ return;
144
+ }
145
+ deps.logger.warn(`a2a: ${method} failed: ${String(error)}`);
146
+ // Internal detail never reaches a peer: it can carry filesystem paths.
147
+ sendJson(res, 200, jsonRpcError(id, ERR_INVALID_REQUEST, 'internal error'));
148
+ }
149
+ };
150
+ /**
151
+ * Resolve the context a request addresses, creating one when none was named.
152
+ *
153
+ * A context owned by another peer is reported exactly as an absent one, so a
154
+ * peer cannot enumerate context ids by comparing responses.
155
+ */
156
+ const resolveContext = async (rawContextId, peer) => {
157
+ if (rawContextId === undefined)
158
+ return deps.createActivation(peer);
159
+ const found = deps.contexts.lookup(A2AContextId(rawContextId), peer);
160
+ if (found === 'unknown' || found === 'forbidden') {
161
+ throw new A2ARpcError(ERR_INVALID_PARAMS, `unknown contextId: ${rawContextId}`);
162
+ }
163
+ return found;
164
+ };
165
+ /**
166
+ * Find an IN-FLIGHT task slot this peer owns.
167
+ *
168
+ * A settled task has no slot — `settleSlot` removes it — so this is only the
169
+ * first half of a lookup. Operations that merely READ a task fall through to
170
+ * the projection ({@link readTask}); operations that act on a running task
171
+ * (cancel, resubscribe) need the live slot and stop here.
172
+ */
173
+ const requireSlot = (rawTaskId, peer) => {
174
+ const found = findSlot(rawTaskId, peer);
175
+ if (found === undefined)
176
+ throw taskNotFound(requireTaskId(rawTaskId));
177
+ return found;
178
+ };
179
+ /** Locate an in-flight slot this peer owns, without throwing when absent. */
180
+ const findSlot = (rawTaskId, peer) => {
181
+ const taskId = requireTaskId(rawTaskId);
182
+ for (const activation of deps.contexts.values()) {
183
+ if (activation.peer !== peer)
184
+ continue;
185
+ const slot = activation.slots.get(taskId);
186
+ if (slot !== undefined)
187
+ return { activation, slot };
188
+ }
189
+ return undefined;
190
+ };
191
+ /** Validate the `taskId` parameter shape. */
192
+ const requireTaskId = (rawTaskId) => {
193
+ if (typeof rawTaskId !== 'string' || rawTaskId.length === 0) {
194
+ throw new A2ARpcError(ERR_INVALID_PARAMS, 'taskId is required');
195
+ }
196
+ return rawTaskId;
197
+ };
198
+ /**
199
+ * Read a task's current state, live slot or not.
200
+ *
201
+ * Falls back to the durable projection, which is what makes `tasks/get`
202
+ * answerable after settlement — and, once persistence is composed, after a
203
+ * restart. A task belonging to another peer reports exactly like an absent
204
+ * one, so ownership cannot be probed by comparing responses.
205
+ */
206
+ const readTask = (rawTaskId, peer) => {
207
+ const taskId = requireTaskId(rawTaskId);
208
+ for (const activation of deps.contexts.values()) {
209
+ if (activation.peer !== peer)
210
+ continue;
211
+ const slot = activation.slots.get(taskId);
212
+ if (slot !== undefined) {
213
+ const state = slot.turn === undefined ? 'submitted' : 'working';
214
+ return deps.taskSnapshot(activation, slot, state, redactArtifacts(slot.texts.length > 0
215
+ ? [{
216
+ artifactId: `${taskId}-result`,
217
+ parts: [{ kind: 'text', text: slot.texts.join('\n') }],
218
+ }]
219
+ : []));
220
+ }
221
+ const projected = deps.readProjectedTask?.(activation, taskId);
222
+ // Text read back from the log leaves the process just like live text
223
+ // does, so it goes through the same scrub.
224
+ if (projected !== undefined) {
225
+ return { ...projected, artifacts: redactArtifacts(projected.artifacts ?? []) };
226
+ }
227
+ }
228
+ throw taskNotFound(taskId);
229
+ };
230
+ const dispatch = async (operation, dialect, id, params, peer, res) => {
231
+ switch (operation) {
232
+ case 'send':
233
+ case 'stream': {
234
+ const parsed = parseSendParams(params);
235
+ if (parsed === undefined)
236
+ throw new A2ARpcError(ERR_INVALID_PARAMS, 'message is required');
237
+ const raw = partsToText(parsed.message.parts);
238
+ if (raw.trim().length === 0) {
239
+ throw new A2ARpcError(ERR_INVALID_PARAMS, 'message carries no readable content');
240
+ }
241
+ const activation = await resolveContext(parsed.message.contextId, peer);
242
+ const turn = deps.turns.track(activation.contextId);
243
+ if (turn > config.maxContextTurns) {
244
+ const rejected = deps.taskSnapshot(activation, { taskId: 'rejected' }, 'rejected', [{
245
+ artifactId: 'rejected',
246
+ parts: [{
247
+ kind: 'text',
248
+ text: `context ${activation.contextId} exceeded ${config.maxContextTurns} turns; `
249
+ + 'start a new context or raise maxContextTurns',
250
+ }],
251
+ }]);
252
+ sendJson(res, 200, jsonRpcResult(id, renderTask(rejected, dialect)));
253
+ return;
254
+ }
255
+ const slot = await deps.submit(activation, filterInbound(raw), peer);
256
+ if (operation === 'stream') {
257
+ openStream(res, id, dialect, slot, activation);
258
+ return;
259
+ }
260
+ // A2A is async-first: `message/send` MAY answer with a non-terminal
261
+ // task. Whether it waits is negotiated, not fixed — the client asks
262
+ // through `configuration.blocking`, and the deployment's `sendMode` is
263
+ // only the default for a client that expresses no preference.
264
+ //
265
+ // The spec lets the server decline a blocking request ("The server may
266
+ // reject this if the task is long-running"), which is exactly what the
267
+ // timeout below does: the task keeps running and the peer polls.
268
+ const requested = parsed.configuration?.blocking;
269
+ const shouldBlock = requested ?? config.sendMode === 'block';
270
+ const settlement = shouldBlock
271
+ ? await withTimeout(slot.settled, config.blockTimeoutMs)
272
+ : undefined;
273
+ const task = settlement === undefined
274
+ // Not an error: the peer polls tasks/get or resubscribes, and the task
275
+ // keeps running. Erroring here would discard real work.
276
+ ? deps.taskSnapshot(activation, slot, 'working', [])
277
+ : deps.taskSnapshot(activation, slot, settlement.state, redactArtifacts(settlement.artifacts), settlement.stopReason);
278
+ sendJson(res, 200, jsonRpcResult(id, renderTask(task, dialect)));
279
+ return;
280
+ }
281
+ case 'get': {
282
+ const task = readTask(params?.['taskId'], peer);
283
+ sendJson(res, 200, jsonRpcResult(id, renderTask(task, dialect)));
284
+ return;
285
+ }
286
+ case 'cancel': {
287
+ const { activation, slot } = requireSlot(params?.['taskId'], peer);
288
+ if (slot.done)
289
+ throw new A2ARpcError(ERR_TASK_NOT_CANCELABLE, 'task already reached a terminal state');
290
+ deps.cancel(activation, slot);
291
+ const task = deps.taskSnapshot(activation, slot, 'canceled', []);
292
+ sendJson(res, 200, jsonRpcResult(id, renderTask(task, dialect)));
293
+ return;
294
+ }
295
+ case 'resubscribe': {
296
+ const rawTaskId = params?.['taskId'];
297
+ const live = findSlot(rawTaskId, peer);
298
+ if (live !== undefined) {
299
+ openStream(res, id, dialect, live.slot, live.activation);
300
+ return;
301
+ }
302
+ // Already settled: a peer that reconnects after the fact still deserves
303
+ // the outcome. Emit the terminal transition from the projection and
304
+ // close, rather than claiming the task never existed.
305
+ const task = readTask(rawTaskId, peer);
306
+ openSettledStream(res, id, dialect, task);
307
+ return;
308
+ }
309
+ case 'push_set':
310
+ case 'push_get':
311
+ case 'push_list':
312
+ case 'push_delete': {
313
+ // Advertised as unsupported on the card, so a compliant peer never
314
+ // reaches this; answering with the spec's own code keeps one that does
315
+ // from guessing.
316
+ throw new A2ARpcError(config.push.enabled ? ERR_UNSUPPORTED_OPERATION : ERR_PUSH_NOT_SUPPORTED, 'push notifications are not enabled on this deployment');
317
+ }
318
+ default:
319
+ throw new A2ARpcError(ERR_METHOD_NOT_FOUND, `unsupported operation: ${operation}`);
320
+ }
321
+ };
322
+ /** Open an SSE stream and push this task's terminal transition when it settles. */
323
+ const openStream = (res, id, dialect, slot, activation) => {
324
+ res.writeHead(200, {
325
+ 'content-type': 'text/event-stream',
326
+ 'cache-control': 'no-cache',
327
+ connection: 'keep-alive',
328
+ });
329
+ const channel = {
330
+ res, id, dialect, taskId: slot.taskId, contextId: activation.contextId,
331
+ };
332
+ streams.add(channel);
333
+ res.write(sseFrame(id, renderStatusUpdate({
334
+ kind: 'status-update',
335
+ taskId: slot.taskId,
336
+ contextId: activation.contextId,
337
+ status: { state: slot.turn === undefined ? 'submitted' : 'working', timestamp: nowIso() },
338
+ final: false,
339
+ }, dialect)));
340
+ void slot.settled.then((settlement) => {
341
+ if (!streams.has(channel))
342
+ return;
343
+ for (const artifact of redactArtifacts(settlement.artifacts)) {
344
+ res.write(sseFrame(id, { kind: 'artifact-update', taskId: slot.taskId, contextId: activation.contextId, artifact, lastChunk: true }));
345
+ }
346
+ res.write(sseFrame(id, renderStatusUpdate({
347
+ kind: 'status-update',
348
+ taskId: slot.taskId,
349
+ contextId: activation.contextId,
350
+ status: { state: settlement.state, timestamp: nowIso() },
351
+ final: true,
352
+ }, dialect)));
353
+ streams.delete(channel);
354
+ res.end();
355
+ });
356
+ };
357
+ /**
358
+ * Answer a resubscribe for an already-settled task: one terminal frame, then close.
359
+ * @param res - the HTTP response to stream over.
360
+ * @param id - the JSON-RPC id to correlate frames with.
361
+ * @param dialect - the dialect the peer spoke.
362
+ * @param task - the settled task, read from the projection.
363
+ */
364
+ const openSettledStream = (res, id, dialect, task) => {
365
+ res.writeHead(200, {
366
+ 'content-type': 'text/event-stream',
367
+ 'cache-control': 'no-cache',
368
+ connection: 'keep-alive',
369
+ });
370
+ res.write(sseFrame(id, renderStatusUpdate({
371
+ kind: 'status-update',
372
+ taskId: task.id,
373
+ contextId: task.contextId,
374
+ status: task.status,
375
+ final: true,
376
+ }, dialect)));
377
+ res.end();
378
+ };
379
+ const closeStreams = () => {
380
+ for (const channel of streams) {
381
+ try {
382
+ channel.res.write(sseFrame(channel.id, renderStatusUpdate({
383
+ kind: 'status-update',
384
+ taskId: channel.taskId,
385
+ contextId: A2AContextId(channel.contextId),
386
+ status: { state: 'canceled', timestamp: nowIso() },
387
+ final: true,
388
+ }, channel.dialect)));
389
+ channel.res.end();
390
+ }
391
+ catch {
392
+ // A socket already gone needs no farewell.
393
+ }
394
+ }
395
+ streams.clear();
396
+ };
397
+ return { serveCard, serveRpc, closeStreams };
398
+ }
399
+ /**
400
+ * Scrub credential-shaped text from artifacts before they leave the process.
401
+ * @param artifacts - the artifacts about to be sent.
402
+ * @returns artifacts with text parts redacted.
403
+ */
404
+ function redactArtifacts(artifacts) {
405
+ return artifacts.map(artifact => ({
406
+ ...artifact,
407
+ parts: artifact.parts.map(part => part.kind === 'text' ? { kind: 'text', text: redactOutbound(part.text) } : part),
408
+ }));
409
+ }
410
+ /**
411
+ * Await a promise, resolving to undefined if it takes too long.
412
+ *
413
+ * A timeout is NOT an error here: the task keeps running and the peer polls.
414
+ * @param promise - the settlement to await.
415
+ * @param ms - the budget.
416
+ * @returns the settlement, or undefined on timeout.
417
+ */
418
+ async function withTimeout(promise, ms) {
419
+ let timer;
420
+ const timeout = new Promise((resolve) => {
421
+ timer = setTimeout(() => { resolve(undefined); }, ms);
422
+ timer.unref?.();
423
+ });
424
+ try {
425
+ return await Promise.race([promise, timeout]);
426
+ }
427
+ finally {
428
+ if (timer !== undefined)
429
+ clearTimeout(timer);
430
+ }
431
+ }
432
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Authentication, rate limiting, inbound defanging, and outbound redaction.
3
+ *
4
+ * The real security boundary is not in this file: it is the sandbox scope and
5
+ * the deterministically-rejected approval an A2A agent runs under. Injection
6
+ * defanging here is noise reduction, and must never be cited as a reason to
7
+ * widen what a peer-driven agent is allowed to do.
8
+ *
9
+ * @module dsh-a2a/security
10
+ */
11
+ /** Who a request is from. The value comes only from the presented credential. */
12
+ export type PeerIdentity = string;
13
+ /**
14
+ * Compare two secrets without leaking their relationship through timing.
15
+ * @param a - the presented value.
16
+ * @param b - the stored value.
17
+ * @returns whether they are byte-identical.
18
+ */
19
+ export declare function constantTimeEqual(a: string, b: string): boolean;
20
+ /**
21
+ * Extract the bearer token from an Authorization header.
22
+ * @param header - the raw header value, if any.
23
+ * @returns the token, or undefined when absent or not a bearer scheme.
24
+ */
25
+ export declare function parseBearer(header: string | undefined): string | undefined;
26
+ /**
27
+ * Resolve the presented token to a declared peer identity.
28
+ *
29
+ * Every candidate is compared even after a match, so response time does not
30
+ * reveal which peer matched or how many peers are declared.
31
+ * @param token - the presented bearer token, if any.
32
+ * @param credentials - declared peer name to its resolved secret.
33
+ * @returns the matched identity, or undefined.
34
+ */
35
+ export declare function identifyPeer(token: string | undefined, credentials: ReadonlyMap<PeerIdentity, string>): PeerIdentity | undefined;
36
+ /** Sliding-window request counter, keyed by authenticated identity. */
37
+ export declare class RateLimiter {
38
+ private readonly perMinute;
39
+ private readonly now;
40
+ private readonly hits;
41
+ /**
42
+ * @param perMinute - allowed requests per identity per rolling minute.
43
+ * @param now - clock injection point for tests.
44
+ */
45
+ constructor(perMinute: number, now?: () => number);
46
+ /**
47
+ * Record a request and report whether it is within budget.
48
+ * @param identity - the authenticated peer.
49
+ * @returns true when the request may proceed.
50
+ */
51
+ allow(identity: PeerIdentity): boolean;
52
+ /** Drop all counters; used on teardown. */
53
+ clear(): void;
54
+ }
55
+ /** Per-context turn counter that stops one peer from looping a context forever. */
56
+ export declare class TurnTracker {
57
+ private readonly turns;
58
+ /**
59
+ * Count one inbound message on a context.
60
+ * @param contextId - the context being extended.
61
+ * @returns the turn number this message occupies, starting at 1.
62
+ */
63
+ track(contextId: string): number;
64
+ /**
65
+ * Reset a context's counter, as an explicit cancellation should.
66
+ * @param contextId - the context to reset.
67
+ */
68
+ reset(contextId: string): void;
69
+ /** Drop all counters; used on teardown. */
70
+ clear(): void;
71
+ }
72
+ /** What a defanged marker is replaced with. */
73
+ export declare const FILTERED = "[filtered]";
74
+ /**
75
+ * Defang prompt-injection markers in inbound task text.
76
+ * @param text - the peer's raw text.
77
+ * @returns the text with markers replaced.
78
+ */
79
+ export declare function filterInbound(text: string): string;
80
+ /**
81
+ * Scrub credential-shaped substrings before text leaves this process.
82
+ *
83
+ * This applies to REPLIES, not just to a hypothetical outbound client: an
84
+ * inbound-only server still ships model-authored text to a peer.
85
+ * @param text - the text about to be sent.
86
+ * @returns the scrubbed text.
87
+ */
88
+ export declare function redactOutbound(text: string): string;
89
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,iFAAiF;AACjF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAA;AAEjC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAW/D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,WAAW,EAAE,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC,GAC7C,YAAY,GAAG,SAAS,CAO1B;AAED,uEAAuE;AACvE,qBAAa,WAAW;IAQpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IARtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;IAEzD;;;OAGG;gBAEgB,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAM,MAAiB;IAG/C;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO;IAYtC,2CAA2C;IAC3C,KAAK,IAAI,IAAI;CAGd;AAED,mFAAmF;AACnF,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAElD;;;;OAIG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAMhC;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI9B,2CAA2C;IAC3C,KAAK,IAAI,IAAI;CAGd;AAkBD,+CAA+C;AAC/C,eAAO,MAAM,QAAQ,eAAe,CAAA;AAEpC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlD;AAaD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAInD"}