nexus-ai-pro 2.2.0 → 2.3.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 (135) hide show
  1. package/API_STABILITY.md +39 -0
  2. package/CHANGELOG.md +142 -1
  3. package/README.md +10 -5
  4. package/dist/agent/capabilities.d.ts +39 -0
  5. package/dist/agent/capabilities.js +36 -0
  6. package/dist/agent/create-agent.d.ts +61 -11
  7. package/dist/agent/create-agent.js +136 -22
  8. package/dist/agent/index.d.ts +3 -2
  9. package/dist/agent/index.js +1 -1
  10. package/dist/agent/middleware/approval.d.ts +26 -0
  11. package/dist/agent/middleware/approval.js +23 -0
  12. package/dist/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
  13. package/dist/agent/{middleware.js → middleware/basic.js} +3 -5
  14. package/dist/agent/middleware/context-editor.d.ts +52 -0
  15. package/dist/agent/middleware/context-editor.js +66 -0
  16. package/dist/agent/middleware/filesystem.d.ts +44 -0
  17. package/dist/agent/middleware/filesystem.js +83 -0
  18. package/dist/agent/middleware/index.d.ts +19 -0
  19. package/dist/agent/middleware/index.js +9 -0
  20. package/dist/agent/middleware/limits.d.ts +42 -0
  21. package/dist/agent/middleware/limits.js +52 -0
  22. package/dist/agent/middleware/models.d.ts +48 -0
  23. package/dist/agent/middleware/models.js +44 -0
  24. package/dist/agent/middleware/pii.d.ts +67 -0
  25. package/dist/agent/middleware/pii.js +173 -0
  26. package/dist/agent/middleware/retry.d.ts +66 -0
  27. package/dist/agent/middleware/retry.js +59 -0
  28. package/dist/agent/middleware/shared.d.ts +41 -0
  29. package/dist/agent/middleware/shared.js +73 -0
  30. package/dist/agent/middleware/tool-selector.d.ts +64 -0
  31. package/dist/agent/middleware/tool-selector.js +106 -0
  32. package/dist/agent/permissions.d.ts +113 -0
  33. package/dist/agent/permissions.js +180 -0
  34. package/dist/agent/sandbox.d.ts +151 -0
  35. package/dist/agent/sandbox.js +257 -0
  36. package/dist/agent/tool.d.ts +8 -3
  37. package/dist/agent/tool.js +14 -3
  38. package/dist/deep-agent/index.d.ts +109 -0
  39. package/dist/deep-agent/index.js +216 -0
  40. package/dist/graph/functional.d.ts +9 -0
  41. package/dist/graph/functional.js +20 -3
  42. package/dist/graph/graph.js +25 -4
  43. package/dist/graph/lint.d.ts +4 -1
  44. package/dist/graph/lint.js +35 -0
  45. package/dist/postgres/fulltext.d.ts +67 -0
  46. package/dist/postgres/fulltext.js +91 -0
  47. package/dist/rag/elasticsearch.d.ts +71 -0
  48. package/dist/rag/elasticsearch.js +130 -0
  49. package/dist/rag/pipeline.d.ts +140 -0
  50. package/dist/rag/pipeline.js +187 -0
  51. package/dist/rag/rerankers.d.ts +92 -0
  52. package/dist/rag/rerankers.js +97 -0
  53. package/dist/rag/retrievers.d.ts +12 -1
  54. package/dist/server/assistant.d.ts +5 -1
  55. package/dist/server/assistant.js +4 -2
  56. package/dist/server/auth.d.ts +250 -0
  57. package/dist/server/auth.js +392 -0
  58. package/dist/store/memory.d.ts +10 -0
  59. package/dist/store/memory.js +10 -0
  60. package/dist/types/graph.d.ts +38 -0
  61. package/dist/types/messages.d.ts +36 -2
  62. package/dist/types/principal.d.ts +21 -0
  63. package/dist/types/principal.js +1 -0
  64. package/dist/types/server.d.ts +2 -9
  65. package/dist/utils/tenant.d.ts +11 -0
  66. package/dist/utils/tenant.js +14 -0
  67. package/dist/version.d.ts +1 -1
  68. package/dist/version.js +1 -1
  69. package/dist-cjs/agent/capabilities.d.ts +39 -0
  70. package/dist-cjs/agent/capabilities.js +41 -0
  71. package/dist-cjs/agent/create-agent.d.ts +61 -11
  72. package/dist-cjs/agent/create-agent.js +136 -22
  73. package/dist-cjs/agent/index.d.ts +3 -2
  74. package/dist-cjs/agent/index.js +4 -4
  75. package/dist-cjs/agent/middleware/approval.d.ts +26 -0
  76. package/dist-cjs/agent/middleware/approval.js +26 -0
  77. package/dist-cjs/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
  78. package/dist-cjs/agent/{middleware.js → middleware/basic.js} +3 -5
  79. package/dist-cjs/agent/middleware/context-editor.d.ts +52 -0
  80. package/dist-cjs/agent/middleware/context-editor.js +70 -0
  81. package/dist-cjs/agent/middleware/filesystem.d.ts +44 -0
  82. package/dist-cjs/agent/middleware/filesystem.js +86 -0
  83. package/dist-cjs/agent/middleware/index.d.ts +19 -0
  84. package/dist-cjs/agent/middleware/index.js +28 -0
  85. package/dist-cjs/agent/middleware/limits.d.ts +42 -0
  86. package/dist-cjs/agent/middleware/limits.js +57 -0
  87. package/dist-cjs/agent/middleware/models.d.ts +48 -0
  88. package/dist-cjs/agent/middleware/models.js +48 -0
  89. package/dist-cjs/agent/middleware/pii.d.ts +67 -0
  90. package/dist-cjs/agent/middleware/pii.js +178 -0
  91. package/dist-cjs/agent/middleware/retry.d.ts +66 -0
  92. package/dist-cjs/agent/middleware/retry.js +63 -0
  93. package/dist-cjs/agent/middleware/shared.d.ts +41 -0
  94. package/dist-cjs/agent/middleware/shared.js +83 -0
  95. package/dist-cjs/agent/middleware/tool-selector.d.ts +64 -0
  96. package/dist-cjs/agent/middleware/tool-selector.js +109 -0
  97. package/dist-cjs/agent/permissions.d.ts +113 -0
  98. package/dist-cjs/agent/permissions.js +189 -0
  99. package/dist-cjs/agent/sandbox.d.ts +151 -0
  100. package/dist-cjs/agent/sandbox.js +297 -0
  101. package/dist-cjs/agent/tool.d.ts +8 -3
  102. package/dist-cjs/agent/tool.js +14 -3
  103. package/dist-cjs/deep-agent/index.d.ts +109 -0
  104. package/dist-cjs/deep-agent/index.js +219 -0
  105. package/dist-cjs/graph/functional.d.ts +9 -0
  106. package/dist-cjs/graph/functional.js +20 -3
  107. package/dist-cjs/graph/graph.js +25 -4
  108. package/dist-cjs/graph/lint.d.ts +4 -1
  109. package/dist-cjs/graph/lint.js +35 -0
  110. package/dist-cjs/postgres/fulltext.d.ts +67 -0
  111. package/dist-cjs/postgres/fulltext.js +129 -0
  112. package/dist-cjs/rag/elasticsearch.d.ts +71 -0
  113. package/dist-cjs/rag/elasticsearch.js +135 -0
  114. package/dist-cjs/rag/pipeline.d.ts +140 -0
  115. package/dist-cjs/rag/pipeline.js +191 -0
  116. package/dist-cjs/rag/rerankers.d.ts +92 -0
  117. package/dist-cjs/rag/rerankers.js +107 -0
  118. package/dist-cjs/rag/retrievers.d.ts +12 -1
  119. package/dist-cjs/server/assistant.d.ts +5 -1
  120. package/dist-cjs/server/assistant.js +4 -2
  121. package/dist-cjs/server/auth.d.ts +250 -0
  122. package/dist-cjs/server/auth.js +402 -0
  123. package/dist-cjs/store/memory.d.ts +10 -0
  124. package/dist-cjs/store/memory.js +10 -0
  125. package/dist-cjs/types/graph.d.ts +38 -0
  126. package/dist-cjs/types/messages.d.ts +36 -2
  127. package/dist-cjs/types/principal.d.ts +21 -0
  128. package/dist-cjs/types/principal.js +2 -0
  129. package/dist-cjs/types/server.d.ts +2 -9
  130. package/dist-cjs/utils/tenant.d.ts +11 -0
  131. package/dist-cjs/utils/tenant.js +15 -0
  132. package/dist-cjs/version.d.ts +1 -1
  133. package/dist-cjs/version.js +1 -1
  134. package/llms.txt +4 -3
  135. package/package.json +118 -1
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RerankerError = void 0;
4
+ exports.httpReranker = httpReranker;
5
+ exports.cohereReranker = cohereReranker;
6
+ exports.voyageReranker = voyageReranker;
7
+ exports.jinaReranker = jinaReranker;
8
+ exports.teiReranker = teiReranker;
9
+ exports.crossEncoderReranker = crossEncoderReranker;
10
+ const signals_js_1 = require("../utils/signals.js");
11
+ class RerankerError extends Error {
12
+ status;
13
+ body;
14
+ constructor(message, status, body) {
15
+ super(message);
16
+ this.status = status;
17
+ this.body = body;
18
+ this.name = 'RerankerError';
19
+ }
20
+ }
21
+ exports.RerankerError = RerankerError;
22
+ function httpReranker(options) {
23
+ const fetchImpl = options.fetch ?? globalThis.fetch;
24
+ const limit = options.maxChunkCharacters ?? 4_000;
25
+ return async (query, chunks, signal) => {
26
+ if (chunks.length === 0)
27
+ return [];
28
+ const passages = chunks.map((chunk) => chunk.content.slice(0, limit));
29
+ const linked = (0, signals_js_1.linkSignals)([AbortSignal.timeout(options.timeoutMs ?? 30_000), signal]);
30
+ try {
31
+ const response = await fetchImpl(options.url, {
32
+ method: 'POST',
33
+ headers: { 'content-type': 'application/json', ...options.headers },
34
+ body: JSON.stringify(options.body(query, passages)),
35
+ signal: linked.signal,
36
+ });
37
+ const text = await response.text();
38
+ if (!response.ok)
39
+ throw new RerankerError(`The rerank API answered ${response.status}`, response.status, text);
40
+ const scores = new Array(chunks.length).fill(0);
41
+ for (const { index, score } of options.scores(JSON.parse(text))) {
42
+ if (Number.isInteger(index) && index >= 0 && index < scores.length)
43
+ scores[index] = Number(score);
44
+ }
45
+ return scores;
46
+ }
47
+ finally {
48
+ linked.dispose();
49
+ }
50
+ };
51
+ }
52
+ const bearer = (options) => ({ authorization: `Bearer ${options.apiKey}`, ...options.headers });
53
+ const readScored = (list) => (list ?? []).map((item) => ({ index: item.index, score: item.relevance_score }));
54
+ function cohereReranker(options) {
55
+ return httpReranker({
56
+ ...options,
57
+ url: options.url ?? 'https://api.cohere.com/v2/rerank',
58
+ headers: bearer(options),
59
+ body: (query, documents) => ({ model: options.model, query, documents, top_n: documents.length }),
60
+ scores: (response) => readScored(response.results),
61
+ });
62
+ }
63
+ function voyageReranker(options) {
64
+ return httpReranker({
65
+ ...options,
66
+ url: options.url ?? 'https://api.voyageai.com/v1/rerank',
67
+ headers: bearer(options),
68
+ body: (query, documents) => ({ model: options.model, query, documents, top_k: documents.length }),
69
+ scores: (response) => readScored(response.data),
70
+ });
71
+ }
72
+ function jinaReranker(options) {
73
+ return httpReranker({
74
+ ...options,
75
+ url: options.url ?? 'https://api.jina.ai/v1/rerank',
76
+ headers: bearer(options),
77
+ body: (query, documents) => ({ model: options.model, query, documents, top_n: documents.length }),
78
+ scores: (response) => readScored(response.results),
79
+ });
80
+ }
81
+ function teiReranker(options) {
82
+ return httpReranker({
83
+ ...options,
84
+ url: `${options.url.replace(/\/+$/, '')}/rerank`,
85
+ body: (query, texts) => ({ query, texts, raw_scores: false, truncate: true }),
86
+ scores: (response) => response,
87
+ });
88
+ }
89
+ function crossEncoderReranker(model, options = {}) {
90
+ const batchSize = Math.max(1, options.batchSize ?? 32);
91
+ const limit = options.maxChunkCharacters ?? 2_000;
92
+ return async (query, chunks, signal) => {
93
+ const pairs = chunks.map((chunk) => [query, chunk.content.slice(0, limit)]);
94
+ const scores = [];
95
+ for (let start = 0; start < pairs.length; start += batchSize) {
96
+ signal?.throwIfAborted();
97
+ const batch = pairs.slice(start, start + batchSize);
98
+ const result = await model.score(batch);
99
+ if (result.length !== batch.length) {
100
+ throw new RangeError(`The cross-encoder returned ${result.length} scores for ${batch.length} pairs`);
101
+ }
102
+ for (const raw of result)
103
+ scores.push(options.sigmoid ? 1 / (1 + Math.exp(-raw)) : raw);
104
+ }
105
+ return scores;
106
+ };
107
+ }
@@ -19,6 +19,17 @@ export interface Retriever {
19
19
  /** The chunks that best answer a query, best first. */
20
20
  retrieve(query: string, options?: RetrieveOptions): Promise<VectorSearchResult[]>;
21
21
  }
22
+ /**
23
+ * Keyword search that holds its own chunks: an in-memory BM25 `KeywordIndex`, Postgres full-text
24
+ * search, a search engine. It is a `Retriever`, so `hybridRetriever()` fuses it with vector search,
25
+ * and it takes writes, so ingestion keeps it in step with a vector store.
26
+ */
27
+ export interface SparseRetriever extends Retriever {
28
+ /** Adds chunks, or replaces those whose id exists. */
29
+ add(chunks: readonly RagChunk[]): Promise<void> | void;
30
+ /** Removes chunks by id. An id that is not held is ignored. */
31
+ delete(ids: readonly string[]): Promise<void> | void;
32
+ }
22
33
  /** A client that runs one completion — a `NexusAI` instance, or anything with the same `complete()`. */
23
34
  export interface RetrievalModelClient {
24
35
  /** Runs one completion and returns its text. */
@@ -47,7 +58,7 @@ export declare function tokenize(text: string): string[];
47
58
  * codes, error numbers, names — that keyword search finds; `hybridRetriever()` fuses the two.
48
59
  * Adding a chunk whose id exists replaces it, as in a vector store.
49
60
  */
50
- export declare class KeywordIndex implements Retriever {
61
+ export declare class KeywordIndex implements SparseRetriever {
51
62
  private readonly chunks;
52
63
  private readonly postings;
53
64
  private totalLength;
@@ -1,5 +1,5 @@
1
1
  import type { GraphStreamProjection } from '../types/graph.js';
2
- import type { AssistantRunContext, ServerAssistant } from '../types/server.js';
2
+ import type { AssistantRunContext, Principal, ServerAssistant } from '../types/server.js';
3
3
  /**
4
4
  * The part of a compiled graph the adapter uses.
5
5
  *
@@ -13,6 +13,7 @@ export interface GraphLike {
13
13
  signal?: AbortSignal;
14
14
  metadata?: Record<string, unknown>;
15
15
  tenantId?: string;
16
+ principal?: Principal;
16
17
  control?: DrainSwitch;
17
18
  }): AsyncIterable<unknown>;
18
19
  /** Answers an interrupt and continues the thread. */
@@ -20,6 +21,7 @@ export interface GraphLike {
20
21
  signal?: AbortSignal;
21
22
  metadata?: Record<string, unknown>;
22
23
  tenantId?: string;
24
+ principal?: Principal;
23
25
  control?: DrainSwitch;
24
26
  }): AsyncIterable<unknown>;
25
27
  /** The thread's checkpoint, at its latest step or at one given. */
@@ -34,6 +36,7 @@ export interface GraphLike {
34
36
  signal?: AbortSignal;
35
37
  metadata?: Record<string, unknown>;
36
38
  tenantId?: string;
39
+ principal?: Principal;
37
40
  control?: DrainSwitch;
38
41
  }): AsyncIterable<unknown>;
39
42
  /** Writes values into a thread's state, which is how a rollback is applied. */
@@ -51,6 +54,7 @@ export interface GraphLike {
51
54
  type GraphEventOptionsLike = {
52
55
  threadId?: string;
53
56
  tenantId?: string;
57
+ principal?: Principal;
54
58
  signal?: AbortSignal;
55
59
  metadata?: Record<string, unknown>;
56
60
  control?: DrainSwitch;
@@ -85,8 +85,10 @@ function functionAssistant(run, options = {}) {
85
85
  };
86
86
  }
87
87
  function tenantOf(context) {
88
- const tenantId = context.principal?.tenantId;
89
- return tenantId ? { tenantId } : {};
88
+ const principal = context.principal;
89
+ if (!principal)
90
+ return {};
91
+ return { ...(principal.tenantId ? { tenantId: principal.tenantId } : {}), principal };
90
92
  }
91
93
  async function* withResult(events) {
92
94
  for await (const event of events)
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Authentication for the agent server: JSON Web Tokens, API keys, and a trusted proxy.
3
+ *
4
+ * Each builds the `authenticate` hook of `createAgentServer()`, and each returns the same
5
+ * `Principal`: a subject, a tenant, roles, and scopes. That principal is what scopes threads, runs,
6
+ * budgets, and the store to a tenant, and what reaches every graph node, tool, and middleware of the
7
+ * run. Everything is built on Web Crypto, so there is no dependency and it runs wherever `fetch` does.
8
+ */
9
+ import type { webcrypto } from 'node:crypto';
10
+ import type { Principal } from '../types/principal.js';
11
+ type JsonWebKey = webcrypto.JsonWebKey;
12
+ type CryptoKey = webcrypto.CryptoKey;
13
+ /** The `authenticate` hook of `createAgentServer()`. */
14
+ export type AuthHook = (request: Request) => Promise<Principal | Response | undefined> | Principal | Response | undefined;
15
+ /** The signature algorithms a token may use. `none` is never accepted. */
16
+ export type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'PS256' | 'PS384' | 'PS512' | 'ES256' | 'ES384' | 'ES512' | 'EdDSA';
17
+ /** A token's claims, the registered ones typed. */
18
+ export interface JwtPayload {
19
+ /** The issuer. */
20
+ iss?: string;
21
+ /** The subject: who the token is about. */
22
+ sub?: string;
23
+ /** The audience: who the token is for. */
24
+ aud?: string | string[];
25
+ /** Expiry, in seconds since the epoch. */
26
+ exp?: number;
27
+ /** Not valid before, in seconds since the epoch. */
28
+ nbf?: number;
29
+ /** Issued at, in seconds since the epoch. */
30
+ iat?: number;
31
+ /** The token's id. */
32
+ jti?: string;
33
+ /** Every other claim. */
34
+ [claim: string]: unknown;
35
+ }
36
+ /** A token's header. */
37
+ export interface JwtHeader {
38
+ /** The signature algorithm. */
39
+ alg: string;
40
+ /** The id of the key that signed it, for choosing one from a key set. */
41
+ kid?: string;
42
+ /** The token type, usually `JWT`. */
43
+ typ?: string;
44
+ /** Any other header field. */
45
+ [field: string]: unknown;
46
+ }
47
+ /** A verified token. */
48
+ export interface VerifiedJwt {
49
+ /** Its header. */
50
+ header: JwtHeader;
51
+ /** Its claims, each checked. */
52
+ payload: JwtPayload;
53
+ }
54
+ /** Why a token was refused. */
55
+ export type JwtErrorCode = 'JWT_MALFORMED' | 'JWT_ALGORITHM' | 'JWT_KEY' | 'JWT_SIGNATURE' | 'JWT_EXPIRED' | 'JWT_NOT_YET_VALID' | 'JWT_TOO_OLD' | 'JWT_ISSUER' | 'JWT_AUDIENCE' | 'JWT_CLAIM';
56
+ /** Thrown when a token is refused: malformed, signed wrongly, expired, or for someone else. */
57
+ export declare class JwtError extends Error {
58
+ /** Why. */
59
+ readonly code: JwtErrorCode;
60
+ constructor(
61
+ /** Why. */
62
+ code: JwtErrorCode, message: string);
63
+ }
64
+ /** Options for `createJwtVerifier()`. Give it one key source: `secret`, `publicKey`, or `jwks`. */
65
+ export interface JwtVerifyOptions {
66
+ /** A shared secret, for HS256, HS384, and HS512. */
67
+ secret?: string | Uint8Array;
68
+ /** One public key: PEM (`-----BEGIN PUBLIC KEY-----`), a JWK, or a `CryptoKey`. */
69
+ publicKey?: string | JsonWebKey | CryptoKey;
70
+ /**
71
+ * The identity provider's key set: its URL, or the keys themselves. Fetched keys are cached, and
72
+ * a token naming a key not yet seen fetches the set again, so a provider's key rotation needs no
73
+ * restart.
74
+ */
75
+ jwks?: string | URL | {
76
+ keys: JsonWebKey[];
77
+ };
78
+ /**
79
+ * The algorithms accepted. Defaults to HS256, HS384, and HS512 for a secret and to every
80
+ * asymmetric algorithm for a public key or a key set. A shared secret is never accepted for an
81
+ * asymmetric algorithm, nor a public key for HMAC, so one cannot be passed off as the other.
82
+ */
83
+ algorithms?: readonly JwtAlgorithm[];
84
+ /** The issuer a token must name: one, or any of several. */
85
+ issuer?: string | readonly string[];
86
+ /**
87
+ * The audience a token must be for: one, or any of several. Required with `jwks`, where a
88
+ * provider signs tokens for every application it serves; `false` accepts any audience,
89
+ * deliberately.
90
+ */
91
+ audience?: string | readonly string[] | false;
92
+ /** Seconds of clock difference tolerated on `exp`, `nbf`, and `iat`. Defaults to 60. */
93
+ clockToleranceSec?: number;
94
+ /** The oldest a token may be, from its `iat`, in seconds. */
95
+ maxAgeSec?: number;
96
+ /** Requires an `exp` claim. Defaults to true: a token that never expires is refused. */
97
+ requireExpiry?: boolean;
98
+ /** Claims a token must carry, besides `exp`. */
99
+ requiredClaims?: readonly string[];
100
+ /** How long a fetched key set is kept, in milliseconds. Defaults to 10 minutes. */
101
+ jwksCacheMs?: number;
102
+ /**
103
+ * The least time between two fetches for keys not yet seen, in milliseconds, so tokens naming keys
104
+ * that do not exist cannot make the server hammer the provider. Defaults to 30 seconds.
105
+ */
106
+ jwksCooldownMs?: number;
107
+ /** Fetches the key set. Defaults to the global `fetch`. */
108
+ fetch?: (input: string | URL, init?: RequestInit) => Promise<Response>;
109
+ /** Replaces the clock, in milliseconds since the epoch, for tests. */
110
+ now?: () => number;
111
+ }
112
+ /** A reusable verifier: it keeps imported keys and the fetched key set between tokens. */
113
+ export interface JwtVerifier {
114
+ /** Verifies a token: its form, its signature, and its claims. Throws `JwtError` when it is refused. */
115
+ verify(token: string): Promise<VerifiedJwt>;
116
+ }
117
+ /**
118
+ * Builds a verifier for tokens from one issuer.
119
+ *
120
+ * ```ts
121
+ * const verifier = createJwtVerifier({
122
+ * jwks: 'https://login.example.com/.well-known/jwks.json',
123
+ * issuer: 'https://login.example.com/',
124
+ * audience: 'agents-api',
125
+ * });
126
+ * const { payload } = await verifier.verify(token);
127
+ * ```
128
+ */
129
+ export declare function createJwtVerifier(options: JwtVerifyOptions): JwtVerifier;
130
+ /** Which claims a principal is read from. A dot reaches into a nested claim: `realm_access.roles`. */
131
+ export interface JwtClaimNames {
132
+ /** The subject. Defaults to `sub`. */
133
+ subject?: string;
134
+ /** The tenant. Defaults to `tenant_id`. */
135
+ tenant?: string;
136
+ /** The roles, as a list or a space-separated string. Defaults to `roles`. */
137
+ roles?: string;
138
+ /** The scopes, as a space-separated string or a list. Defaults to `scope`, then `scp`. */
139
+ scopes?: string;
140
+ }
141
+ /** Options for `jwtAuth()`. */
142
+ export interface JwtAuthOptions extends JwtVerifyOptions {
143
+ /** Reads the token from a request. Defaults to `Authorization: Bearer <token>`; a cookie works too. */
144
+ token?: (request: Request) => string | undefined;
145
+ /** Which claims the principal is read from. */
146
+ claims?: JwtClaimNames;
147
+ /**
148
+ * Builds the principal from the verified claims instead, for a mapping of your own. Returning
149
+ * nothing refuses the request with 403: the token is valid, but not for this server.
150
+ */
151
+ principal?: (payload: JwtPayload, request: Request) => Principal | undefined | Promise<Principal | undefined>;
152
+ }
153
+ /**
154
+ * Authenticates requests by a JSON Web Token: an identity provider's, through its key set, or your
155
+ * own, signed with a shared secret.
156
+ *
157
+ * A request with no token is passed over, so another hook in `anyAuth()` can try. A token that is
158
+ * refused answers 401 with a `WWW-Authenticate` challenge naming why, and a valid one becomes a
159
+ * `Principal`: its subject, tenant, roles, and scopes, with `method: 'jwt'` and the verified claims.
160
+ *
161
+ * ```ts
162
+ * createAgentServer({
163
+ * assistants,
164
+ * authenticate: jwtAuth({
165
+ * jwks: 'https://login.example.com/.well-known/jwks.json',
166
+ * issuer: 'https://login.example.com/',
167
+ * audience: 'agents-api',
168
+ * claims: { tenant: 'org_id', roles: 'realm_access.roles' },
169
+ * }),
170
+ * });
171
+ * ```
172
+ */
173
+ export declare function jwtAuth(options: JwtAuthOptions): AuthHook;
174
+ /** Options for `apiKeyAuth()`. Give it `keys`, `lookup`, or both. */
175
+ export interface ApiKeyAuthOptions {
176
+ /**
177
+ * Keys by their SHA-256 hash, from `hashApiKey()`, each with the principal it stands for. The keys
178
+ * themselves are never written into configuration.
179
+ */
180
+ keys?: Readonly<Record<string, Principal>>;
181
+ /** Looks a key up by its hash, in a database or a secret store, when `keys` does not have it. */
182
+ lookup?: (hash: string, request: Request) => Principal | undefined | Promise<Principal | undefined>;
183
+ /** The header the key is read from. Defaults to `x-api-key`, then `Authorization: Bearer`. */
184
+ header?: string;
185
+ /**
186
+ * Only a credential with this prefix is taken for a key, such as `nxk_`, so a token in the same
187
+ * header is left to another hook. Without it, anything shaped like a JWT is left alone.
188
+ */
189
+ prefix?: string;
190
+ }
191
+ /** The SHA-256 of an API key, as hex: what `apiKeyAuth({ keys })` is configured with. */
192
+ export declare function hashApiKey(key: string): Promise<string>;
193
+ /**
194
+ * Authenticates requests by an API key, for services and scripts rather than people.
195
+ *
196
+ * Keys are compared by their hash, so configuration and the database hold hashes only. A request
197
+ * with no key is passed over; an unknown key answers 401. The principal is the one the key maps to,
198
+ * with `method: 'api-key'`.
199
+ *
200
+ * ```ts
201
+ * apiKeyAuth({ keys: { [await hashApiKey(process.env.CI_KEY)]: { userId: 'ci', tenantId: 'acme', scopes: ['write'] } } })
202
+ * ```
203
+ */
204
+ export declare function apiKeyAuth(options: ApiKeyAuthOptions): AuthHook;
205
+ /** The headers a proxy names the caller in. */
206
+ export interface TrustedProxyHeaders {
207
+ /** The user. Defaults to `x-forwarded-user`. */
208
+ user?: string;
209
+ /** The tenant. Defaults to `x-forwarded-tenant`. */
210
+ tenant?: string;
211
+ /** The roles. Defaults to `x-forwarded-roles`. */
212
+ roles?: string;
213
+ /** The scopes. Defaults to `x-forwarded-scopes`. */
214
+ scopes?: string;
215
+ }
216
+ /** Options for `trustedProxyAuth()`. Give it `secret`, `trust`, or both. */
217
+ export interface TrustedProxyAuthOptions {
218
+ /** A header the proxy sets to a shared secret, which proves the request came through it. */
219
+ secret?: {
220
+ header: string;
221
+ value: string;
222
+ };
223
+ /** Decides whether a request came through the proxy, by a check of your own. */
224
+ trust?: (request: Request) => boolean | Promise<boolean>;
225
+ /** The headers the caller is named in. */
226
+ headers?: TrustedProxyHeaders;
227
+ /** What separates several roles or scopes in one header. Defaults to a comma; spaces are trimmed. */
228
+ separator?: string;
229
+ }
230
+ /**
231
+ * Takes the caller from headers an authenticating proxy sets: an identity-aware proxy, an API
232
+ * gateway, a service mesh.
233
+ *
234
+ * Headers are only as trustworthy as the path a request took, so this refuses to exist without a
235
+ * proof that the proxy sent the request: a shared secret it adds, a check of your own, or both. A
236
+ * request without that proof, or without a user, is passed over. The principal carries
237
+ * `method: 'proxy'`.
238
+ */
239
+ export declare function trustedProxyAuth(options: TrustedProxyAuthOptions): AuthHook;
240
+ /**
241
+ * Tries hooks in order and takes the first principal: tokens for people and keys for services on
242
+ * one server. When none accepts the request, the first refusal any of them gave is the answer, so a
243
+ * caller learns why their credential was refused.
244
+ *
245
+ * ```ts
246
+ * authenticate: anyAuth(jwtAuth({ ... }), apiKeyAuth({ ... }))
247
+ * ```
248
+ */
249
+ export declare function anyAuth(...hooks: AuthHook[]): AuthHook;
250
+ export {};