ankka 0.11.0 → 0.13.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/README.md +1 -0
- package/dist/_proto/ankka/protocol/v1/client_pb.d.ts +910 -0
- package/dist/_proto/ankka/protocol/v1/client_pb.js +239 -23
- package/dist/_proto/ankka/protocol/v1/consumer_pb.d.ts +10 -1
- package/dist/_proto/ankka/protocol/v1/consumer_pb.js +1 -1
- package/dist/_proto/ankka/protocol/v1/discovery_pb.d.ts +177 -0
- package/dist/_proto/ankka/protocol/v1/discovery_pb.js +51 -36
- package/dist/_proto/ankka/protocol/v1/endpoint_pb.d.ts +26 -0
- package/dist/_proto/ankka/protocol/v1/endpoint_pb.js +15 -10
- package/dist/_proto/ankka/protocol/v1/event_sourced_pb.d.ts +86 -0
- package/dist/_proto/ankka/protocol/v1/event_sourced_pb.js +11 -1
- package/dist/_proto/ankka/protocol/v1/mcp_pb.d.ts +120 -0
- package/dist/_proto/ankka/protocol/v1/mcp_pb.js +29 -0
- package/dist/_proto/ankka/protocol/v1/payload_pb.d.ts +61 -0
- package/dist/_proto/ankka/protocol/v1/payload_pb.js +18 -1
- package/dist/_proto/ankka/protocol/v1/view_pb.d.ts +7 -1
- package/dist/_proto/ankka/protocol/v1/view_pb.js +1 -1
- package/dist/_proto/ankka/protocol/v1/wasm_pb.d.ts +12 -0
- package/dist/_proto/ankka/protocol/v1/wasm_pb.js +1 -1
- package/dist/agent.d.ts +10 -0
- package/dist/agent.js +20 -0
- package/dist/autonomous.d.ts +5 -0
- package/dist/autonomous.js +10 -0
- package/dist/client-keys.d.ts +89 -0
- package/dist/client-keys.js +182 -0
- package/dist/client.d.ts +96 -3
- package/dist/client.js +228 -6
- package/dist/consumer.d.ts +23 -1
- package/dist/consumer.js +25 -1
- package/dist/context.d.ts +25 -1
- package/dist/context.js +5 -2
- package/dist/contract.d.ts +4 -0
- package/dist/contract.js +2 -0
- package/dist/effects/common.d.ts +7 -0
- package/dist/effects/common.js +9 -1
- package/dist/effects/eventSourced.d.ts +26 -1
- package/dist/effects/eventSourced.js +58 -5
- package/dist/endpoint.d.ts +10 -0
- package/dist/endpoint.js +20 -0
- package/dist/eventSourcedEntity.d.ts +8 -3
- package/dist/graph.d.ts +14 -1
- package/dist/graph.js +17 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.js +8 -2
- package/dist/keyedView.d.ts +4 -1
- package/dist/keyedView.js +7 -1
- package/dist/kinds.js +2 -0
- package/dist/mcp-endpoint.d.ts +144 -0
- package/dist/mcp-endpoint.js +256 -0
- package/dist/routes.d.ts +46 -3
- package/dist/routes.js +56 -3
- package/dist/server/discovery.d.ts +12 -0
- package/dist/server/discovery.js +115 -4
- package/dist/server/eventSourced.d.ts +4 -1
- package/dist/server/eventSourced.js +24 -6
- package/dist/server/http.d.ts +8 -0
- package/dist/server/http.js +12 -4
- package/dist/server/mcp.d.ts +17 -0
- package/dist/server/mcp.js +157 -0
- package/dist/server/server.d.ts +11 -1
- package/dist/server/server.js +19 -0
- package/dist/server/stateless.js +5 -4
- package/dist/server/storageEndpoint.d.ts +14 -0
- package/dist/server/storageEndpoint.js +82 -0
- package/dist/service.d.ts +12 -1
- package/dist/service.js +73 -5
- package/dist/sigv4.d.ts +47 -0
- package/dist/sigv4.js +149 -0
- package/dist/spec.d.ts +8 -2
- package/dist/spec.js +62 -6
- package/dist/standing.d.ts +18 -0
- package/dist/standing.js +26 -0
- package/dist/startFrom.d.ts +4 -0
- package/dist/startFrom.js +8 -1
- package/dist/storage.d.ts +288 -0
- package/dist/storage.js +1081 -0
- package/dist/testkit/index.d.ts +1 -1
- package/dist/testkit/integration.d.ts +9 -0
- package/dist/testkit/integration.js +5 -1
- package/dist/testkit/kinds.d.ts +25 -9
- package/dist/testkit/kinds.js +53 -28
- package/dist/testkit/unit.d.ts +31 -3
- package/dist/testkit/unit.js +55 -11
- package/dist/timedAction.d.ts +10 -0
- package/dist/timedAction.js +20 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/view.d.ts +18 -3
- package/dist/view.js +13 -4
- package/dist/workflow.d.ts +8 -0
- package/dist/workflow.js +15 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { EncodingError, DecodingError, renderDouble } from "./json.ts";
|
|
|
5
5
|
export { Instant, Duration, LocalDate, LocalDateTime } from "./time.ts";
|
|
6
6
|
export { ErrorCode, CommandError, Outcome, Retention, httpStatusOf, type ErrorDetail, type Metadata, type EffectLike, type ReadOnlyLike } from "./effects/common.ts";
|
|
7
7
|
export { command, query, stream, step, action, tool, guardrail, type HandlerRef, type ToolRef, type GuardrailRef, type GuardrailStage, type HandlerTable } from "./handlers.ts";
|
|
8
|
-
export { PersistBuilder, EventSourcedEffects, type PersistEffect, type ReadOnlyEffect, type EventSourcedEffect } from "./effects/eventSourced.ts";
|
|
8
|
+
export { PersistBuilder, EventSourcedEffects, type PersistEffect, type ReadOnlyEffect, type EventSourcedEffect, type ReplicationChange } from "./effects/eventSourced.ts";
|
|
9
9
|
export { EventSourcedEntity, type EventSourcedEntityClass } from "./eventSourcedEntity.ts";
|
|
10
10
|
export { UpdateBuilder, KeyValueEffects, type UpdateEffect, type KeyValueReadOnlyEffect, type KeyValueEffect } from "./effects/keyValue.ts";
|
|
11
11
|
export { KeyValueEntity, type KeyValueEntityClass } from "./keyValueEntity.ts";
|
|
@@ -25,15 +25,21 @@ export { ApprovalAwaited, APPROVALS_SINCE, type AgentOutcome, type Approval, typ
|
|
|
25
25
|
export { mcpServer, resultGuardrail, toolName, type McpServerOptions, type McpServerRef, type ResultGuardrailRef } from "./mcp.ts";
|
|
26
26
|
export { AutonomousAgent, AutonomousAgentCalls, TaskCalls, Tasks, accepted, rejected, taskAcceptance, taskRule, taskType, type Accepted, type AgentState, type Attachment, type AutonomousAgentClass, type AutonomousSettings, type Notification, type Rejected, type TaskAcceptance, type TaskRule, type TaskSnapshot, type TaskType, } from "./autonomous.ts";
|
|
27
27
|
export { Endpoint, type EndpointClass } from "./endpoint.ts";
|
|
28
|
+
export { McpEndpoint, ToolTable, tools, MCP_ENDPOINTS_SINCE, type McpEndpointClass, type DeclaredTool, type ToolOptions, type ReferenceOptions, type RegisteredMcpEndpoint, type RegisteredMcpTool, type ToolRun, } from "./mcp-endpoint.ts";
|
|
29
|
+
export { ClientKeys, InMemoryClientKeys, Expiry, CLIENT_KEYS_SINCE, type IssueClientKey, type IssuedClientKey, type ClientKeySummary, } from "./client-keys.ts";
|
|
28
30
|
export { type Socket, SocketClosed } from "./socket.ts";
|
|
29
|
-
export { Acl, Callers, type CallerMatcher, type CallersAcl, HttpProblem, get, post, put, patch, del, sse, sseEvent, type SseEvent, socket, type RouteRef, type RouteOptions, type RouteTable, type Params, type ParamNames, type HttpMethod } from "./routes.ts";
|
|
30
|
-
export { type CommandContext, type RequestContext, type Principal, type Caller, Query, Headers } from "./context.ts";
|
|
31
|
-
export { ComponentClient, Calls, TypedCalls, Invocation, Views, Timers, Secrets, InMemorySecrets, noSecrets, type TimerTarget, type TimedActionTarget, type ComponentRef } from "./client.ts";
|
|
31
|
+
export { Acl, Callers, type CallerMatcher, type CallersAcl, type AnyOfAcl, HttpProblem, get, post, put, patch, del, sse, sseEvent, sseEvents, type SseEvent, socket, type RouteRef, type RouteOptions, type RouteTable, type Params, type ParamNames, type HttpMethod } from "./routes.ts";
|
|
32
|
+
export { type CommandContext, type EventContext, type RequestContext, type Principal, type Caller, Query, Headers } from "./context.ts";
|
|
33
|
+
export { ComponentClient, Calls, TypedCalls, Invocation, AwaitingInvocation, AWAIT_SINCE, awaitPartJson, Views, Timers, Secrets, InMemorySecrets, noSecrets, WatchEnded, VIEW_STREAMS_SINCE, type AwaitPart, type WatchEvent, type WatchOptions, type Overflow, type TimerTarget, type TimedActionTarget, type ComponentRef } from "./client.ts";
|
|
34
|
+
export { ObjectRules, StorageRefusals, InMemoryBuckets, DirectoryBuckets, S3Buckets, S3Bucket, noStorage, chooseStorage, declaredBuckets, processStorage, s3Settings, bucketNameOf, bucketVariableSuffix, localAddress, STORAGE_PATH, type Buckets, type Bucket, type BucketExposure, type SignedAccess, type StoredObject, type ObjectInfo, type ObjectEntry, type PutOptions, type InMemoryBucketsOptions, type DirectoryBucketsOptions, type DeclaredBuckets, type S3Settings, type S3Target, type NamedTarget, type StorageBackend, type ChosenStorage, type StorageChoiceOptions, } from "./storage.ts";
|
|
35
|
+
export { Credentials, SignedRequest, sign as signRequest, presign as presignUrl } from "./sigv4.ts";
|
|
32
36
|
export { Services, ServiceClient, ScriptedServices, noServices, ServiceError, ServiceUnresolvable, ServiceIdentityMismatch, ServiceUnanswered, ServiceCallFailed, type ServiceResponse, type ServiceRequest, type ServiceHeaders, } from "./services.ts";
|
|
33
37
|
export { Ankka, ServiceBuilder, Registry, RegistrationError, type ServiceOptions, type RegisteredComponent, type RegisteredEndpoint, type Source, type RegisteredEventSourced, type RegisteredKeyValue, type RegisteredWorkflow, type RegisteredView, type RegisteredKeyedView, type RegisteredKeyedSource, type RegisteredConsumer, type RegisteredTimedAction, type RegisteredAgent, } from "./service.ts";
|
|
34
38
|
export { Server, type ServerOptions } from "./server/server.ts";
|
|
35
39
|
export { problems as sidecarProblems } from "./server/discovery.ts";
|
|
40
|
+
export { createMcpDispatcher, type McpDispatcher, type ToolAnswer } from "./server/mcp.ts";
|
|
36
41
|
export { PROTOCOL_VERSION, SDK_NAME } from "./spec.ts";
|
|
37
42
|
export { StartFrom } from "./startFrom.ts";
|
|
43
|
+
export { isTerminal, isUnknown, type Standing, type StandingStatus } from "./standing.ts";
|
|
38
44
|
export { materialiseEventSourced, materialiseKeyValue, materialiseWorkflowCommand, materialiseStep, type Materialised, type MaterialisedKeyValue, type MaterialisedWorkflowCommand, type MaterialisedStep, } from "./materialise.ts";
|
|
39
45
|
export type { ComponentKind } from "./kinds.ts";
|
package/dist/index.js
CHANGED
|
@@ -36,14 +36,20 @@ export { ApprovalAwaited, APPROVALS_SINCE } from "./approvals.js";
|
|
|
36
36
|
export { mcpServer, resultGuardrail, toolName } from "./mcp.js";
|
|
37
37
|
export { AutonomousAgent, AutonomousAgentCalls, TaskCalls, Tasks, accepted, rejected, taskAcceptance, taskRule, taskType, } from "./autonomous.js";
|
|
38
38
|
export { Endpoint } from "./endpoint.js";
|
|
39
|
+
export { McpEndpoint, ToolTable, tools, MCP_ENDPOINTS_SINCE, } from "./mcp-endpoint.js";
|
|
40
|
+
export { ClientKeys, InMemoryClientKeys, Expiry, CLIENT_KEYS_SINCE, } from "./client-keys.js";
|
|
39
41
|
export { SocketClosed } from "./socket.js";
|
|
40
|
-
export { Acl, Callers, HttpProblem, get, post, put, patch, del, sse, sseEvent, socket } from "./routes.js";
|
|
42
|
+
export { Acl, Callers, HttpProblem, get, post, put, patch, del, sse, sseEvent, sseEvents, socket } from "./routes.js";
|
|
41
43
|
export { Query, Headers } from "./context.js";
|
|
42
|
-
export { ComponentClient, Calls, TypedCalls, Invocation, Views, Timers, Secrets, InMemorySecrets, noSecrets } from "./client.js";
|
|
44
|
+
export { ComponentClient, Calls, TypedCalls, Invocation, AwaitingInvocation, AWAIT_SINCE, awaitPartJson, Views, Timers, Secrets, InMemorySecrets, noSecrets, WatchEnded, VIEW_STREAMS_SINCE } from "./client.js";
|
|
45
|
+
export { ObjectRules, StorageRefusals, InMemoryBuckets, DirectoryBuckets, S3Buckets, S3Bucket, noStorage, chooseStorage, declaredBuckets, processStorage, s3Settings, bucketNameOf, bucketVariableSuffix, localAddress, STORAGE_PATH, } from "./storage.js";
|
|
46
|
+
export { Credentials, SignedRequest, sign as signRequest, presign as presignUrl } from "./sigv4.js";
|
|
43
47
|
export { Services, ServiceClient, ScriptedServices, noServices, ServiceError, ServiceUnresolvable, ServiceIdentityMismatch, ServiceUnanswered, ServiceCallFailed, } from "./services.js";
|
|
44
48
|
export { Ankka, ServiceBuilder, Registry, RegistrationError, } from "./service.js";
|
|
45
49
|
export { Server } from "./server/server.js";
|
|
46
50
|
export { problems as sidecarProblems } from "./server/discovery.js";
|
|
51
|
+
export { createMcpDispatcher } from "./server/mcp.js";
|
|
47
52
|
export { PROTOCOL_VERSION, SDK_NAME } from "./spec.js";
|
|
48
53
|
export { StartFrom } from "./startFrom.js";
|
|
54
|
+
export { isTerminal, isUnknown } from "./standing.js";
|
|
49
55
|
export { materialiseEventSourced, materialiseKeyValue, materialiseWorkflowCommand, materialiseStep, } from "./materialise.js";
|
package/dist/keyedView.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Metadata } from "./effects/common.ts";
|
|
|
3
3
|
import type { ComponentClient, ComponentRef } from "./client.ts";
|
|
4
4
|
import { KeyedViewEffects, type KeyedViewEffect } from "./effects/keyed.ts";
|
|
5
5
|
import type { DeclaredQuery } from "./view.ts";
|
|
6
|
+
import type { Standing } from "./standing.ts";
|
|
6
7
|
type MaybePromise<T> = T | Promise<T>;
|
|
7
8
|
/** A keyed view's own rows, for the length of one change. It reaches no other view. */
|
|
8
9
|
export interface ViewRows<Row> {
|
|
@@ -32,13 +33,15 @@ export declare abstract class KeyedView<Row> {
|
|
|
32
33
|
get metadata(): Metadata;
|
|
33
34
|
/** The id of the entity the change came from. */
|
|
34
35
|
get subject(): string;
|
|
36
|
+
/** Of a change from a workflow: where it stood once the effect that recorded the state was applied. `undefined` for a change from an entity or a topic. */
|
|
37
|
+
get standing(): Standing | undefined;
|
|
35
38
|
/** This view's own rows, by key or by one of its declared queries. */
|
|
36
39
|
get rows(): ViewRows<Row>;
|
|
37
40
|
get client(): ComponentClient;
|
|
38
41
|
/** @internal */
|
|
39
42
|
get _kind(): "view";
|
|
40
43
|
/** @internal */
|
|
41
|
-
_bind(metadata: Metadata, client: ComponentClient | undefined, rows: ViewRows<Row
|
|
44
|
+
_bind(metadata: Metadata, client: ComponentClient | undefined, rows: ViewRows<Row>, standing?: Standing): void;
|
|
42
45
|
}
|
|
43
46
|
export interface KeyedViewClass<Row = unknown, C extends KeyedView<Row> = KeyedView<Row>> {
|
|
44
47
|
new (): C;
|
package/dist/keyedView.js
CHANGED
|
@@ -26,6 +26,7 @@ export function on(source, events, onChange, options = {}) {
|
|
|
26
26
|
export class KeyedView {
|
|
27
27
|
effects = new KeyedViewEffects();
|
|
28
28
|
#metadata = {};
|
|
29
|
+
#standing = undefined;
|
|
29
30
|
#client;
|
|
30
31
|
#rows;
|
|
31
32
|
/** The change's metadata: `ce-subject` is the source entity's id, `ankka.sequence` its sequence number. */
|
|
@@ -36,6 +37,10 @@ export class KeyedView {
|
|
|
36
37
|
get subject() {
|
|
37
38
|
return this.#metadata["ce-subject"] ?? "";
|
|
38
39
|
}
|
|
40
|
+
/** Of a change from a workflow: where it stood once the effect that recorded the state was applied. `undefined` for a change from an entity or a topic. */
|
|
41
|
+
get standing() {
|
|
42
|
+
return this.#standing;
|
|
43
|
+
}
|
|
39
44
|
/** This view's own rows, by key or by one of its declared queries. */
|
|
40
45
|
get rows() {
|
|
41
46
|
if (!this.#rows)
|
|
@@ -52,8 +57,9 @@ export class KeyedView {
|
|
|
52
57
|
return "view";
|
|
53
58
|
}
|
|
54
59
|
/** @internal */
|
|
55
|
-
_bind(metadata, client, rows) {
|
|
60
|
+
_bind(metadata, client, rows, standing) {
|
|
56
61
|
this.#metadata = metadata;
|
|
62
|
+
this.#standing = standing;
|
|
57
63
|
this.#client = client;
|
|
58
64
|
this.#rows = rows;
|
|
59
65
|
}
|
package/dist/kinds.js
CHANGED
|
@@ -30,6 +30,8 @@ const CODE_TO_PROTO = Object.freeze({
|
|
|
30
30
|
CONFLICT: ProtoErrorCode.CONFLICT,
|
|
31
31
|
TIMEOUT: ProtoErrorCode.TIMEOUT,
|
|
32
32
|
UNAVAILABLE: ProtoErrorCode.UNAVAILABLE,
|
|
33
|
+
WORKFLOW_FAILED: ProtoErrorCode.WORKFLOW_FAILED,
|
|
34
|
+
NOT_HOME: ProtoErrorCode.NOT_HOME,
|
|
33
35
|
});
|
|
34
36
|
export function errorCodeToProto(code) {
|
|
35
37
|
return CODE_TO_PROTO[code];
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { type Codec, type Shape } from "./codec.ts";
|
|
2
|
+
import type { ComponentRef } from "./client.ts";
|
|
3
|
+
import { Endpoint } from "./endpoint.ts";
|
|
4
|
+
import type { HandlerRef } from "./handlers.ts";
|
|
5
|
+
import { type Acl, type HttpMethod, type RouteRef } from "./routes.ts";
|
|
6
|
+
import type { ComponentKind } from "./kinds.ts";
|
|
7
|
+
import type { EndpointClass } from "./endpoint.ts";
|
|
8
|
+
import type { RegisteredComponent, RegisteredEndpoint } from "./service.ts";
|
|
9
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
10
|
+
/** The first protocol whose runtime serves a process's MCP endpoint. */
|
|
11
|
+
export declare const MCP_ENDPOINTS_SINCE = "1.20";
|
|
12
|
+
/** What a tool name may be: what MCP clients accept everywhere. */
|
|
13
|
+
export declare const TOOL_NAME: RegExp;
|
|
14
|
+
/**
|
|
15
|
+
* The base of an MCP endpoint. One instance serves every call, so the call's principal and caller are
|
|
16
|
+
* on `this.request`, as for an HTTP endpoint; `client`, `secrets`, `services` and `clientKeys` likewise.
|
|
17
|
+
*/
|
|
18
|
+
export declare abstract class McpEndpoint extends Endpoint {
|
|
19
|
+
}
|
|
20
|
+
/** One tool as declared, before its references are resolved. */
|
|
21
|
+
export type DeclaredTool<Ep> = {
|
|
22
|
+
readonly kind: "tool";
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly description: string;
|
|
25
|
+
readonly input: Shape<any>;
|
|
26
|
+
readonly reply: Shape<any> | undefined;
|
|
27
|
+
readonly run: (args: any, self: Ep) => MaybePromise<unknown>;
|
|
28
|
+
readonly acl: Acl | undefined;
|
|
29
|
+
} | {
|
|
30
|
+
readonly kind: "command" | "query";
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly description: string;
|
|
33
|
+
readonly component: ComponentRef;
|
|
34
|
+
readonly handler: string;
|
|
35
|
+
/** The argument holding the entity's or workflow's id. */
|
|
36
|
+
readonly id: string;
|
|
37
|
+
/** The argument holding the handler's input; absent merges a record input's fields beside the id. */
|
|
38
|
+
readonly input: string | undefined;
|
|
39
|
+
readonly acl: Acl | undefined;
|
|
40
|
+
} | {
|
|
41
|
+
readonly kind: "route";
|
|
42
|
+
readonly name: string;
|
|
43
|
+
readonly description: string;
|
|
44
|
+
readonly endpoint: EndpointClass<any>;
|
|
45
|
+
readonly method: HttpMethod;
|
|
46
|
+
/** The full path: the endpoint's prefix and the route's template, `/orders/{day}`. */
|
|
47
|
+
readonly path: string;
|
|
48
|
+
readonly acl: Acl | undefined;
|
|
49
|
+
};
|
|
50
|
+
export interface ToolOptions {
|
|
51
|
+
/** Who may call this tool, beside the endpoint's rule; client keys and `anyOf` are allowed. */
|
|
52
|
+
readonly acl?: Acl;
|
|
53
|
+
}
|
|
54
|
+
export interface ReferenceOptions extends ToolOptions {
|
|
55
|
+
/** The argument that names the entity or workflow. */
|
|
56
|
+
readonly id: string;
|
|
57
|
+
/** The argument holding the handler's input, when it is not to be merged beside the id. */
|
|
58
|
+
readonly input?: string;
|
|
59
|
+
}
|
|
60
|
+
/** The tools of an MCP endpoint, built as `tools<CartMcp>().tool(...).command(...)`. */
|
|
61
|
+
export declare class ToolTable<Ep = McpEndpoint> {
|
|
62
|
+
#private;
|
|
63
|
+
readonly declared: readonly DeclaredTool<Ep>[];
|
|
64
|
+
constructor(declared?: readonly DeclaredTool<Ep>[]);
|
|
65
|
+
/**
|
|
66
|
+
* A tool this process runs: its arguments decoded with `input` (a record schema becomes the tool's
|
|
67
|
+
* object schema), its answer encoded with `reply` (a string answers as text; an object also as
|
|
68
|
+
* structured content). A thrown error or a refusal is the tool error the client is shown.
|
|
69
|
+
*/
|
|
70
|
+
tool<I, R>(name: string, description: string, input: Shape<I>, reply: Shape<R> | undefined, run: (args: I, self: Ep) => MaybePromise<R>, options?: ToolOptions): ToolTable<Ep>;
|
|
71
|
+
/** A tool that runs a command of a component, by its wire name: `command("checkout", "...", ShoppingCart, "checkout", { id: "cartId" })`. */
|
|
72
|
+
command(name: string, description: string, component: ComponentRef, handler: string | HandlerRef<any, any, any, any>, options: ReferenceOptions): ToolTable<Ep>;
|
|
73
|
+
/** A tool that runs a query of a component; it cannot change anything. */
|
|
74
|
+
query(name: string, description: string, component: ComponentRef, handler: string | HandlerRef<any, any, any, any>, options: ReferenceOptions): ToolTable<Ep>;
|
|
75
|
+
/** A tool that calls a route of one of this service's endpoints, in process: its path names are the arguments, and `body` the body. */
|
|
76
|
+
route(name: string, description: string, endpoint: EndpointClass<any>, method: HttpMethod, path: string, options?: ToolOptions): ToolTable<Ep>;
|
|
77
|
+
}
|
|
78
|
+
/** An empty tool table to build on. */
|
|
79
|
+
export declare function tools<Ep = McpEndpoint>(): ToolTable<Ep>;
|
|
80
|
+
/** The statics an MCP endpoint class declares; `register` constrains on this type. */
|
|
81
|
+
export interface McpEndpointClass<C extends McpEndpoint = McpEndpoint> {
|
|
82
|
+
new (): C;
|
|
83
|
+
/** `/mcp`: where the endpoint is served, on the service's own hostnames. */
|
|
84
|
+
readonly path: string;
|
|
85
|
+
/** Who may connect: `Acl.clientKeys`, `Acl.authenticated`, `Acl.anyOf(...)`. There is no default. */
|
|
86
|
+
readonly acl: Acl;
|
|
87
|
+
readonly tools: ToolTable<C>;
|
|
88
|
+
/** The platform signs people in for clients that cannot hold a token (needs `authenticated` in the rule). */
|
|
89
|
+
readonly brokered?: boolean;
|
|
90
|
+
/** The server's name in `initialize`; the class name when absent. */
|
|
91
|
+
readonly serverName?: string;
|
|
92
|
+
readonly serverVersion?: string;
|
|
93
|
+
}
|
|
94
|
+
/** How a resolved tool is run; data the server interprets. */
|
|
95
|
+
export type ToolRun = {
|
|
96
|
+
readonly kind: "function";
|
|
97
|
+
readonly input: Shape<any>;
|
|
98
|
+
readonly reply: Shape<any> | undefined;
|
|
99
|
+
readonly run: (args: any, self: McpEndpoint) => MaybePromise<unknown>;
|
|
100
|
+
} | {
|
|
101
|
+
readonly kind: "handler";
|
|
102
|
+
readonly componentKind: ComponentKind;
|
|
103
|
+
readonly componentId: string;
|
|
104
|
+
readonly handler: HandlerRef<any, any, any, any>;
|
|
105
|
+
readonly id: string;
|
|
106
|
+
/** `merge`: a record input's fields sit beside the id; a name: the input is that argument; absent: there is none. */
|
|
107
|
+
readonly input: {
|
|
108
|
+
readonly kind: "merge";
|
|
109
|
+
} | {
|
|
110
|
+
readonly kind: "argument";
|
|
111
|
+
readonly name: string;
|
|
112
|
+
} | undefined;
|
|
113
|
+
} | {
|
|
114
|
+
readonly kind: "route";
|
|
115
|
+
readonly endpointId: string;
|
|
116
|
+
readonly route: RouteRef<any, any, any, any>;
|
|
117
|
+
readonly paramNames: readonly string[];
|
|
118
|
+
};
|
|
119
|
+
export interface RegisteredMcpTool {
|
|
120
|
+
readonly name: string;
|
|
121
|
+
readonly description: string;
|
|
122
|
+
/** The JSON Schema of the arguments, which the platform checks before the process is asked. */
|
|
123
|
+
readonly inputSchema: Record<string, unknown>;
|
|
124
|
+
readonly acl: Acl | undefined;
|
|
125
|
+
readonly run: ToolRun;
|
|
126
|
+
}
|
|
127
|
+
export interface RegisteredMcpEndpoint {
|
|
128
|
+
readonly id: string;
|
|
129
|
+
readonly cls: McpEndpointClass<any>;
|
|
130
|
+
readonly path: string;
|
|
131
|
+
readonly acl: Acl;
|
|
132
|
+
readonly tools: readonly RegisteredMcpTool[];
|
|
133
|
+
readonly brokered: boolean;
|
|
134
|
+
readonly serverName: string | undefined;
|
|
135
|
+
readonly serverVersion: string | undefined;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Resolves an MCP endpoint class against the registered components and endpoints, collecting every
|
|
139
|
+
* problem. A reference to a component or route that is not registered is refused here, before start.
|
|
140
|
+
*/
|
|
141
|
+
export declare function registerMcpEndpoint(cls: McpEndpointClass<any>, components: ReadonlyMap<string, RegisteredComponent>, endpoints: ReadonlyMap<string, RegisteredEndpoint>, problems: string[]): RegisteredMcpEndpoint | undefined;
|
|
142
|
+
/** The codec a tool's own reply is encoded with, when it declares one. */
|
|
143
|
+
export declare function replyCodecOf(reply: Shape<any> | undefined): Codec<unknown> | undefined;
|
|
144
|
+
export {};
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// An MCP endpoint (protocol 1.20): a path, an access rule and a table of tools, which the platform
|
|
2
|
+
// serves to any MCP client over Streamable HTTP. The platform answers the protocol, verifies the
|
|
3
|
+
// credential (a client key or a token), checks the arguments against each tool's schema and asks this
|
|
4
|
+
// process to run the tool; the process never sees the credential, only the principal it stood for.
|
|
5
|
+
//
|
|
6
|
+
// export class CartMcp extends McpEndpoint {
|
|
7
|
+
// static readonly path = "/mcp"
|
|
8
|
+
// static readonly acl = Acl.anyOf(Acl.clientKeys, Acl.authenticated)
|
|
9
|
+
// static readonly tools = tools<CartMcp>()
|
|
10
|
+
// .tool("get_cart", "Reads one cart", s.record("GetCart", { cartId: s.string }), Cart,
|
|
11
|
+
// (args, ep) => ep.client.of(ShoppingCart, args.cartId).call(ShoppingCart.handlers.getCart).invoke())
|
|
12
|
+
// .command("checkout", "Checks a cart out", ShoppingCart, "checkout", { id: "cartId" })
|
|
13
|
+
// }
|
|
14
|
+
//
|
|
15
|
+
// A tool is either run by this process's own function, or a reference to a component's handler or to
|
|
16
|
+
// a route of one of this service's endpoints. References are resolved at registration, so one that
|
|
17
|
+
// names something not registered stops the service before it starts.
|
|
18
|
+
var _a;
|
|
19
|
+
import { codecFor, isCodec } from "./codec.js";
|
|
20
|
+
import { Endpoint } from "./endpoint.js";
|
|
21
|
+
import { isAcl, parseTemplate } from "./routes.js";
|
|
22
|
+
import { resolve, toJsonSchema } from "./schema.js";
|
|
23
|
+
/** The first protocol whose runtime serves a process's MCP endpoint. */
|
|
24
|
+
export const MCP_ENDPOINTS_SINCE = "1.20";
|
|
25
|
+
/** What a tool name may be: what MCP clients accept everywhere. */
|
|
26
|
+
export const TOOL_NAME = /^[a-z0-9_-]{1,128}$/;
|
|
27
|
+
/**
|
|
28
|
+
* The base of an MCP endpoint. One instance serves every call, so the call's principal and caller are
|
|
29
|
+
* on `this.request`, as for an HTTP endpoint; `client`, `secrets`, `services` and `clientKeys` likewise.
|
|
30
|
+
*/
|
|
31
|
+
export class McpEndpoint extends Endpoint {
|
|
32
|
+
}
|
|
33
|
+
/** The tools of an MCP endpoint, built as `tools<CartMcp>().tool(...).command(...)`. */
|
|
34
|
+
export class ToolTable {
|
|
35
|
+
declared;
|
|
36
|
+
constructor(declared = []) {
|
|
37
|
+
this.declared = Object.freeze([...declared]);
|
|
38
|
+
Object.freeze(this);
|
|
39
|
+
}
|
|
40
|
+
#with(tool) {
|
|
41
|
+
return new _a([...this.declared, Object.freeze(tool)]);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A tool this process runs: its arguments decoded with `input` (a record schema becomes the tool's
|
|
45
|
+
* object schema), its answer encoded with `reply` (a string answers as text; an object also as
|
|
46
|
+
* structured content). A thrown error or a refusal is the tool error the client is shown.
|
|
47
|
+
*/
|
|
48
|
+
tool(name, description, input, reply, run, options) {
|
|
49
|
+
return this.#with({ kind: "tool", name, description, input, reply, run: run, acl: options?.acl });
|
|
50
|
+
}
|
|
51
|
+
/** A tool that runs a command of a component, by its wire name: `command("checkout", "...", ShoppingCart, "checkout", { id: "cartId" })`. */
|
|
52
|
+
command(name, description, component, handler, options) {
|
|
53
|
+
return this.#reference("command", name, description, component, handler, options);
|
|
54
|
+
}
|
|
55
|
+
/** A tool that runs a query of a component; it cannot change anything. */
|
|
56
|
+
query(name, description, component, handler, options) {
|
|
57
|
+
return this.#reference("query", name, description, component, handler, options);
|
|
58
|
+
}
|
|
59
|
+
/** A tool that calls a route of one of this service's endpoints, in process: its path names are the arguments, and `body` the body. */
|
|
60
|
+
route(name, description, endpoint, method, path, options) {
|
|
61
|
+
return this.#with({ kind: "route", name, description, endpoint, method, path, acl: options?.acl });
|
|
62
|
+
}
|
|
63
|
+
#reference(kind, name, description, component, handler, options) {
|
|
64
|
+
const wire = typeof handler === "string" ? handler : handler?.name;
|
|
65
|
+
return this.#with({ kind, name, description, component, handler: wire, id: options?.id, input: options?.input, acl: options?.acl });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
_a = ToolTable;
|
|
69
|
+
/** An empty tool table to build on. */
|
|
70
|
+
export function tools() {
|
|
71
|
+
return new ToolTable();
|
|
72
|
+
}
|
|
73
|
+
function hasTokens(acl) {
|
|
74
|
+
if (acl === "authenticated")
|
|
75
|
+
return true;
|
|
76
|
+
return typeof acl === "object" && acl.kind === "anyOf" && acl.acls.some(hasTokens);
|
|
77
|
+
}
|
|
78
|
+
function objectSchema(properties, required) {
|
|
79
|
+
return { type: "object", properties, required, additionalProperties: false };
|
|
80
|
+
}
|
|
81
|
+
/** The JSON Schema of a tool's own input: an object schema, whatever the shape (a codec admits any object). */
|
|
82
|
+
function inputSchemaOf(input) {
|
|
83
|
+
if (isCodec(input))
|
|
84
|
+
return { type: "object" };
|
|
85
|
+
const schema = toJsonSchema(input);
|
|
86
|
+
if (schema.type !== "object")
|
|
87
|
+
return `its input must be a record, so its arguments are an object; it is ${String(resolve(input).kind)}`;
|
|
88
|
+
return schema;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolves an MCP endpoint class against the registered components and endpoints, collecting every
|
|
92
|
+
* problem. A reference to a component or route that is not registered is refused here, before start.
|
|
93
|
+
*/
|
|
94
|
+
export function registerMcpEndpoint(cls, components, endpoints, problems) {
|
|
95
|
+
const name = typeof cls === "function" && cls.name ? cls.name : String(cls);
|
|
96
|
+
let ok = true;
|
|
97
|
+
const fail = (m) => {
|
|
98
|
+
problems.push(`${name}: ${m}`);
|
|
99
|
+
ok = false;
|
|
100
|
+
};
|
|
101
|
+
const path = cls.path;
|
|
102
|
+
if (typeof path !== "string" || !path.startsWith("/") || (path.length > 1 && path.endsWith("/")) || path.includes("{")) {
|
|
103
|
+
fail(`needs a static path starting with "/", with no parameters and not ending with "/", not ${JSON.stringify(path)}`);
|
|
104
|
+
}
|
|
105
|
+
else if (path.startsWith("/_ankka/"))
|
|
106
|
+
fail(`path ${path} is the platform's`);
|
|
107
|
+
if (!isAcl(cls.acl))
|
|
108
|
+
fail("needs a static acl — Acl.clientKeys, Acl.authenticated, Acl.anyOf(...) or another rule. An unstated access rule is a decision nobody made");
|
|
109
|
+
if (cls.brokered !== undefined && typeof cls.brokered !== "boolean")
|
|
110
|
+
fail("brokered must be true or false");
|
|
111
|
+
if (cls.brokered === true && isAcl(cls.acl) && !hasTokens(cls.acl))
|
|
112
|
+
fail("is brokered, which signs people in with the service's issuer; its acl must admit Acl.authenticated");
|
|
113
|
+
for (const [what, value] of [["serverName", cls.serverName], ["serverVersion", cls.serverVersion]]) {
|
|
114
|
+
if (value !== undefined && (typeof value !== "string" || value.trim() === ""))
|
|
115
|
+
fail(`${what} must be a non-empty string`);
|
|
116
|
+
}
|
|
117
|
+
const table = cls.tools;
|
|
118
|
+
if (!(table instanceof ToolTable)) {
|
|
119
|
+
fail("needs a static tools table: tools().tool(...)");
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
if (table.declared.length === 0)
|
|
123
|
+
fail("declares no tool; an MCP endpoint needs at least one");
|
|
124
|
+
const resolved = [];
|
|
125
|
+
const seen = new Set();
|
|
126
|
+
for (const t of table.declared) {
|
|
127
|
+
const where = `tool '${t.name}'`;
|
|
128
|
+
if (typeof t.name !== "string" || !TOOL_NAME.test(t.name)) {
|
|
129
|
+
fail(`tool '${String(t.name)}' is not a tool name ([a-z0-9_-]+, at most 128 characters)`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (seen.has(t.name))
|
|
133
|
+
fail(`declares the tool '${t.name}' twice`);
|
|
134
|
+
seen.add(t.name);
|
|
135
|
+
if (typeof t.description !== "string" || t.description.trim() === "")
|
|
136
|
+
fail(`${where} needs a description; it is what a model reads to choose it`);
|
|
137
|
+
if (t.acl !== undefined && !isAcl(t.acl))
|
|
138
|
+
fail(`${where}: unknown acl ${JSON.stringify(t.acl)}`);
|
|
139
|
+
const tool = resolveTool(t, where, components, endpoints, fail);
|
|
140
|
+
if (tool)
|
|
141
|
+
resolved.push(tool);
|
|
142
|
+
}
|
|
143
|
+
if (!ok)
|
|
144
|
+
return undefined;
|
|
145
|
+
return Object.freeze({
|
|
146
|
+
id: name,
|
|
147
|
+
cls,
|
|
148
|
+
path,
|
|
149
|
+
acl: cls.acl,
|
|
150
|
+
tools: Object.freeze(resolved),
|
|
151
|
+
brokered: cls.brokered === true,
|
|
152
|
+
serverName: cls.serverName,
|
|
153
|
+
serverVersion: cls.serverVersion,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function resolveTool(t, where, components, endpoints, fail) {
|
|
157
|
+
const base = { name: t.name, description: t.description, acl: t.acl };
|
|
158
|
+
switch (t.kind) {
|
|
159
|
+
case "tool": {
|
|
160
|
+
if (typeof t.run !== "function") {
|
|
161
|
+
fail(`${where}: the handler is not a function`);
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
const schema = typeof t.input === "object" && t.input !== null ? inputSchemaOf(t.input) : "it needs an input shape";
|
|
165
|
+
if (typeof schema === "string") {
|
|
166
|
+
fail(`${where}: ${schema}`);
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
return Object.freeze({ ...base, inputSchema: schema, run: Object.freeze({ kind: "function", input: t.input, reply: t.reply, run: t.run }) });
|
|
170
|
+
}
|
|
171
|
+
case "command":
|
|
172
|
+
case "query": {
|
|
173
|
+
const componentId = t.component?.componentId;
|
|
174
|
+
const registered = typeof componentId === "string" ? components.get(componentId) : undefined;
|
|
175
|
+
if (!registered || registered.cls !== t.component) {
|
|
176
|
+
fail(`${where} refers to the component ${typeof componentId === "string" ? componentId : String(t.component)}, which is not registered`);
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
if (registered.kind !== "event-sourced" && registered.kind !== "key-value" && registered.kind !== "workflow") {
|
|
180
|
+
fail(`${where} refers to ${registered.id}, a ${registered.kind}; a reference names an entity's or a workflow's handler`);
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
const handler = registered.handlers.get(t.handler);
|
|
184
|
+
if (!handler) {
|
|
185
|
+
fail(`${where} refers to the handler '${String(t.handler)}' of ${registered.id}, which it does not declare`);
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
if (t.kind === "query" && !handler.readOnly)
|
|
189
|
+
fail(`${where} is a query of '${handler.name}', which is a command`);
|
|
190
|
+
if (t.kind === "command" && handler.readOnly)
|
|
191
|
+
fail(`${where} is a command of '${handler.name}', which is a query; declare it with query(...)`);
|
|
192
|
+
if (handler.streaming)
|
|
193
|
+
fail(`${where} refers to '${handler.name}', which streams; a tool answers once`);
|
|
194
|
+
if (typeof t.id !== "string" || t.id.trim() === "") {
|
|
195
|
+
fail(`${where} needs the argument that names the ${registered.kind === "workflow" ? "workflow" : "entity"}: { id: "cartId" }`);
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
const properties = { [t.id]: { type: "string", description: `The id of the ${registered.id}` } };
|
|
199
|
+
const required = [t.id];
|
|
200
|
+
let input;
|
|
201
|
+
if (handler.input !== undefined) {
|
|
202
|
+
const shape = handler.input;
|
|
203
|
+
const json = isCodec(shape) ? { type: "object" } : toJsonSchema(shape);
|
|
204
|
+
if (t.input !== undefined || json.type !== "object" || isCodec(shape)) {
|
|
205
|
+
const argument = t.input ?? "input";
|
|
206
|
+
if (argument === t.id)
|
|
207
|
+
fail(`${where}: the id and the input are both the argument '${argument}'`);
|
|
208
|
+
properties[argument] = json;
|
|
209
|
+
required.push(argument);
|
|
210
|
+
input = { kind: "argument", name: argument };
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
const fields = (json.properties ?? {});
|
|
214
|
+
if (t.id in fields)
|
|
215
|
+
fail(`${where}: the input has a field '${t.id}', which is the id's argument; name the input with { input: "..." }`);
|
|
216
|
+
Object.assign(properties, fields);
|
|
217
|
+
required.push(...(json.required ?? []));
|
|
218
|
+
input = { kind: "merge" };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (t.input !== undefined)
|
|
222
|
+
fail(`${where} names an input argument, but '${handler.name}' takes no input`);
|
|
223
|
+
return Object.freeze({
|
|
224
|
+
...base,
|
|
225
|
+
inputSchema: objectSchema(properties, required),
|
|
226
|
+
run: Object.freeze({ kind: "handler", componentKind: registered.kind, componentId: registered.id, handler, id: t.id, input }),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
case "route": {
|
|
230
|
+
const endpoint = [...endpoints.values()].find((e) => e.cls === t.endpoint);
|
|
231
|
+
if (!endpoint) {
|
|
232
|
+
fail(`${where} refers to the endpoint ${typeof t.endpoint === "function" ? t.endpoint.name : String(t.endpoint)}, which is not registered`);
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
const relative = typeof t.path === "string" && t.path.startsWith(endpoint.prefix) ? t.path.slice(endpoint.prefix === "/" ? 0 : endpoint.prefix.length) || "/" : undefined;
|
|
236
|
+
const route = relative === undefined ? undefined : [...endpoint.routes.values()].find((r) => r.method === t.method && r.template === relative);
|
|
237
|
+
if (!route) {
|
|
238
|
+
fail(`${where} refers to ${t.method} ${t.path}, which ${endpoint.id} does not declare`);
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
if (route.streaming || route.socket) {
|
|
242
|
+
fail(`${where} refers to ${t.method} ${t.path}, which streams; a tool answers once`);
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
const paramNames = parseTemplate(route.template);
|
|
246
|
+
const properties = Object.fromEntries(paramNames.map((n) => [n, { type: "string" }]));
|
|
247
|
+
if (route.body !== undefined)
|
|
248
|
+
properties.body = { type: "object" };
|
|
249
|
+
return Object.freeze({ ...base, inputSchema: objectSchema(properties, [...paramNames]), run: Object.freeze({ kind: "route", endpointId: endpoint.id, route, paramNames }) });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/** The codec a tool's own reply is encoded with, when it declares one. */
|
|
254
|
+
export function replyCodecOf(reply) {
|
|
255
|
+
return reply === undefined ? undefined : codecFor(reply);
|
|
256
|
+
}
|
package/dist/routes.d.ts
CHANGED
|
@@ -13,15 +13,20 @@ export type CallerMatcher = {
|
|
|
13
13
|
readonly kind: "anyInProject";
|
|
14
14
|
} | {
|
|
15
15
|
readonly kind: "self";
|
|
16
|
+
} | {
|
|
17
|
+
readonly kind: "granted";
|
|
16
18
|
};
|
|
17
19
|
/**
|
|
18
20
|
* The callers an endpoint can name: `Acl.allowCallers(Callers.internet, Callers.service("orders"))`. A named
|
|
19
|
-
* service is in this service's own project unless `project` names another.
|
|
21
|
+
* service is in this service's own project unless `project` names another. `Callers.granted` is whoever this
|
|
22
|
+
* service's project has granted the route to — a service of another project, or a registered machine
|
|
23
|
+
* (protocol 1.15); a route that does not name it can never be granted.
|
|
20
24
|
*/
|
|
21
25
|
export declare const Callers: Readonly<{
|
|
22
26
|
internet: CallerMatcher;
|
|
23
27
|
anyInProject: CallerMatcher;
|
|
24
28
|
self: CallerMatcher;
|
|
29
|
+
granted: CallerMatcher;
|
|
25
30
|
service(name: string, options?: {
|
|
26
31
|
readonly project?: string;
|
|
27
32
|
}): CallerMatcher;
|
|
@@ -31,25 +36,48 @@ export interface CallersAcl {
|
|
|
31
36
|
readonly kind: "callers";
|
|
32
37
|
readonly callers: readonly CallerMatcher[];
|
|
33
38
|
}
|
|
39
|
+
/** Admitted when any of `acls` admits: an MCP endpoint's rule (protocol 1.20), `Acl.anyOf(Acl.clientKeys, Acl.authenticated)`. */
|
|
40
|
+
export interface AnyOfAcl {
|
|
41
|
+
readonly kind: "anyOf";
|
|
42
|
+
readonly acls: readonly Acl[];
|
|
43
|
+
}
|
|
34
44
|
/**
|
|
35
45
|
* Who may call: everyone, no one, authenticated callers only, or only the callers named. There is no default.
|
|
46
|
+
* An MCP endpoint may also admit a client key issued for it (`Acl.clientKeys`), and any of several rules
|
|
47
|
+
* (`Acl.anyOf`); an HTTP endpoint refuses both at registration.
|
|
36
48
|
*
|
|
37
49
|
* Outside a cluster every caller is `{ kind: "local" }`, and `allowCallers` admits it.
|
|
38
50
|
*/
|
|
39
|
-
export type Acl = "allow-all" | "deny-all" | "authenticated" | CallersAcl;
|
|
51
|
+
export type Acl = "allow-all" | "deny-all" | "authenticated" | "client-keys" | CallersAcl | AnyOfAcl;
|
|
40
52
|
export declare const Acl: Readonly<{
|
|
41
53
|
allowAll: Acl;
|
|
42
54
|
denyAll: Acl;
|
|
43
55
|
authenticated: Acl;
|
|
56
|
+
/** A client key issued for the MCP endpoint (protocol 1.20); its subject and attributes are the principal. */
|
|
57
|
+
clientKeys: Acl;
|
|
44
58
|
allowCallers(first: CallerMatcher, ...rest: CallerMatcher[]): Acl;
|
|
59
|
+
/** Admitted when any of the rules admits; for an MCP endpoint or one of its tools. */
|
|
60
|
+
anyOf(first: Acl, ...rest: Acl[]): Acl;
|
|
45
61
|
}>;
|
|
46
|
-
/** Whether `x` is an access rule: one of the
|
|
62
|
+
/** Whether `x` is an access rule: one of the words, a non-empty callers rule, or a non-empty `anyOf` of rules. */
|
|
47
63
|
export declare function isAcl(x: unknown): x is Acl;
|
|
64
|
+
/** Whether `acl` is one an HTTP endpoint or route can state: neither client keys nor `anyOf`, which are an MCP endpoint's. */
|
|
65
|
+
export declare function isEndpointAcl(acl: Acl): boolean;
|
|
48
66
|
/** Thrown from a route handler to answer a status other than 200 with a plain-text message. */
|
|
49
67
|
export declare class HttpProblem extends Error {
|
|
50
68
|
readonly status: number;
|
|
51
69
|
constructor(status: number, message: string);
|
|
52
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* @internal An answer whose status and content type the handler chooses, its body as given: the
|
|
73
|
+
* directory store's objects, served under the content type each was kept with.
|
|
74
|
+
*/
|
|
75
|
+
export declare class RawReply {
|
|
76
|
+
readonly status: number;
|
|
77
|
+
readonly contentType: string;
|
|
78
|
+
readonly body: Uint8Array;
|
|
79
|
+
constructor(status: number, contentType: string, body: Uint8Array);
|
|
80
|
+
}
|
|
53
81
|
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
54
82
|
type MaybePromise<T> = T | Promise<T>;
|
|
55
83
|
/** The parameter names in a template: `ParamNames<"/{cartId}/items/{productId}">` is `"cartId" | "productId"`. */
|
|
@@ -113,6 +141,21 @@ export interface SseEvent {
|
|
|
113
141
|
readonly name: string;
|
|
114
142
|
readonly value: unknown;
|
|
115
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* A watch as server-sent events, for an `sse` route: each row as `row` carrying the key and the row,
|
|
146
|
+
* each removal as `removed`, the marker as `caught-up`, and a watch that ended with a reason as a last
|
|
147
|
+
* event `ended` carrying it, so a page is told why.
|
|
148
|
+
*/
|
|
149
|
+
export declare function sseEvents<Row>(watch: AsyncIterable<{
|
|
150
|
+
readonly kind: "row";
|
|
151
|
+
readonly key: string;
|
|
152
|
+
readonly row: Row;
|
|
153
|
+
} | {
|
|
154
|
+
readonly kind: "removed";
|
|
155
|
+
readonly key: string;
|
|
156
|
+
} | {
|
|
157
|
+
readonly kind: "caughtUp";
|
|
158
|
+
}>): AsyncIterable<SseEvent>;
|
|
116
159
|
export declare function sseEvent(name: string, value: unknown): SseEvent;
|
|
117
160
|
/** A server-sent-events route: the handler returns an `AsyncIterable<string | SseEvent>`, one frame per string, and may yield an `SseEvent` among them. */
|
|
118
161
|
export declare function sse<Ep, T extends string, PS extends Readonly<Record<string, Schema>> = {}>(template: T, run: (self: Ep, request: RequestContext<Params<T, PS>>) => AsyncIterable<string | SseEvent> | Promise<AsyncIterable<string | SseEvent>>, options?: RouteOptions<PS>): RouteRef<Ep, Params<T, PS>, undefined, never>;
|