holon-sh 0.0.1-dev.7 → 0.0.1-dev.9
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 +96 -67
- package/dist/context.d.ts +55 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +9 -0
- package/dist/context.js.map +1 -0
- package/dist/ext/events.d.ts +268 -0
- package/dist/ext/events.d.ts.map +1 -0
- package/dist/ext/events.js +619 -0
- package/dist/ext/events.js.map +1 -0
- package/dist/ext/files.client.d.ts +50 -0
- package/dist/ext/files.client.d.ts.map +1 -0
- package/dist/ext/files.client.js +359 -0
- package/dist/ext/files.client.js.map +1 -0
- package/dist/ext/files.d.ts +21 -0
- package/dist/ext/files.d.ts.map +1 -0
- package/dist/ext/files.js +3 -0
- package/dist/ext/files.js.map +1 -0
- package/dist/ext/platform.browser.d.ts +4 -0
- package/dist/ext/platform.browser.d.ts.map +1 -0
- package/dist/ext/platform.browser.js +15 -0
- package/dist/ext/platform.browser.js.map +1 -0
- package/dist/ext/platform.node.d.ts +4 -0
- package/dist/ext/platform.node.d.ts.map +1 -0
- package/dist/ext/platform.node.js +45 -0
- package/dist/ext/platform.node.js.map +1 -0
- package/dist/ext/webhooks.d.ts +18 -0
- package/dist/ext/webhooks.d.ts.map +1 -0
- package/dist/ext/webhooks.js +527 -0
- package/dist/ext/webhooks.js.map +1 -0
- package/dist/protocol.d.ts +134 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +32 -0
- package/dist/protocol.js.map +1 -0
- package/dist/runtime.d.ts +72 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +453 -0
- package/dist/runtime.js.map +1 -0
- package/package.json +56 -19
- package/{context.d.ts → src/context.ts} +11 -1
- package/src/ext/events.ts +812 -0
- package/src/ext/files.client.ts +329 -0
- package/src/ext/files.ts +16 -0
- package/src/ext/platform.browser.ts +15 -0
- package/src/ext/platform.node.ts +43 -0
- package/src/ext/webhooks.ts +512 -0
- package/src/protocol.ts +119 -0
- package/src/runtime.ts +467 -0
- package/context.mjs +0 -6
- package/protocol.d.ts +0 -51
- package/runtime.d.ts +0 -47
- package/runtime.mjs +0 -207
- package/validate.mjs +0 -12
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Holon TypeScript SDK
|
|
2
2
|
|
|
3
3
|
[](https://github.com/holon-sh/sdk-ts/actions/workflows/ci.yml)
|
|
4
|
+
[](https://holon-labs.dev/docs/)
|
|
4
5
|
[](https://nodejs.org/en/download)
|
|
5
6
|
[](https://github.com/holon-sh/sdk-ts/blob/main/LICENSE)
|
|
7
|
+
[](https://discord.gg/jXExyBdy)
|
|
6
8
|
|
|
7
9
|
This repository contains the Node.js runtime for [`holon`](https://github.com/holon-sh/cli).
|
|
8
10
|
|
|
@@ -10,14 +12,37 @@ This repository contains the Node.js runtime for [`holon`](https://github.com/ho
|
|
|
10
12
|
|
|
11
13
|
```sh
|
|
12
14
|
npm install holon-sh@dev
|
|
13
|
-
npm install -D holon-types
|
|
15
|
+
npm install -D holon-types typescript
|
|
14
16
|
```
|
|
15
17
|
|
|
16
18
|
`holon-types` is the `holon` CLI. `holon types check` brings its own TypeScript compiler and uses the project's `typescript` when one is installed.
|
|
17
19
|
|
|
20
|
+
## Create an app
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npx create-holon-app foo
|
|
24
|
+
```
|
|
25
|
+
|
|
18
26
|
## Invoking MCP Servers
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
Declare dependencies under `sh.holon.requires` in a [`server.json`](https://modelcontextprotocol.io/registry/quickstart#step-4-create-server-json) beside the server, here the public [Hugging Face](https://huggingface.co/docs/hub/en/hf-mcp-server) MCP server:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"name": "com.example/foo",
|
|
33
|
+
"version": "0.1.0",
|
|
34
|
+
"description": "Example Foo",
|
|
35
|
+
"_meta": {
|
|
36
|
+
"io.modelcontextprotocol.registry/publisher-provided": {
|
|
37
|
+
"sh.holon": {
|
|
38
|
+
"requires": {
|
|
39
|
+
"huggingface": { "url": "https://huggingface.co/mcp" }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
21
46
|
|
|
22
47
|
### Type-checking MCP invocations
|
|
23
48
|
|
|
@@ -25,102 +50,106 @@ The Holon TypeScript SDK allows generation of type-safe MCP clients. See [Exampl
|
|
|
25
50
|
npx holon types check
|
|
26
51
|
```
|
|
27
52
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<details open>
|
|
31
|
-
<summary><h3>Call a tool</h3></summary>
|
|
53
|
+
A wrong tool name or argument is a type error:
|
|
32
54
|
|
|
33
55
|
```ts
|
|
34
56
|
import { apps } from "#holon-sh";
|
|
35
57
|
|
|
36
|
-
|
|
37
|
-
const greeting = await apps.bar.tools.greet({ name }, { timeout: 5000 });
|
|
38
|
-
return greeting.result;
|
|
39
|
-
}
|
|
40
|
-
```
|
|
58
|
+
await apps.huggingface.tools.hub_repo_search({ query: "llama" });
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
await apps.huggingface.tools.hub_repo_search({ limit: "3" });
|
|
61
|
+
// error TS2322: Type 'string' is not assignable to type 'number'.
|
|
43
62
|
|
|
44
|
-
|
|
45
|
-
|
|
63
|
+
await apps.huggingface.tools.hub_repo_details({});
|
|
64
|
+
// error TS2741: Property '"repo_ids"' is missing in type '{}' but required in type '{ config?: string | undefined; limit?: number | undefined; offset?: number | undefined; operations?: ("dataset_preview" | "dataset_structure" | "overview")[] | undefined; repo_ids: string[]; repo_type?: "dataset" | ... 2 more ... | undefined; split?: string | undefined; }'.
|
|
46
65
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
await apps.bar.tools.greet({ name: "world" });
|
|
52
|
-
} catch (error) {
|
|
53
|
-
if (!(error instanceof ToolCallError)) throw error;
|
|
54
|
-
error.message; // includes the server's text
|
|
55
|
-
error.data; // the server's structured content, or its text parsed as JSON
|
|
56
|
-
error.result; // the original MCP result
|
|
57
|
-
}
|
|
66
|
+
await apps.huggingface.tools.hub_search({ query: "llama" });
|
|
67
|
+
// error TS2339: Property 'hub_search' does not exist on type '{ readonly hf_fs: (input: { operations: { args: string[]; cmd: "attach" | "cat" | "find" | "ls" | "search" | "stat"; }[]; }, options?: ToolCallOptions | undefined) => Promise<{ results: ({ ...; } | { ...; })[]; truncated?: boolean | undefined; truncation_reason?: "output_budget" | undefined; }>; readonly hf_whoami: ...'.
|
|
58
68
|
```
|
|
59
69
|
|
|
60
|
-
|
|
70
|
+
## Events
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
<summary><h3>Read the whole result</h3></summary>
|
|
72
|
+
A server tells its clients what happens with [MCP Events](https://github.com/modelcontextprotocol/experimental-ext-triggers-events/blob/main/docs/design-sketch-proposal.md), a draft extension of the MCP Triggers & Events Working Group. The draft may change, and this follows it, so it lives under `ext`: `holon-sh/ext/events` on a server and `ext.events` on a client. Expect what is there to change.
|
|
64
73
|
|
|
65
|
-
|
|
74
|
+
A server declares an event type and emits its occurrences:
|
|
66
75
|
|
|
67
76
|
```ts
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
+
import { createEvents } from "holon-sh/ext/events";
|
|
78
|
+
|
|
79
|
+
const events = createEvents();
|
|
80
|
+
const said = events.event("room.said", {
|
|
81
|
+
description: "Someone said something in a room",
|
|
82
|
+
inputSchema: z.object({ room: z.string() }),
|
|
83
|
+
payloadSchema: z.object({ text: z.string() }),
|
|
84
|
+
match: ({ room }, args) => room === args.room,
|
|
85
|
+
transform: ({ text }) => ({ text }),
|
|
86
|
+
});
|
|
77
87
|
|
|
78
|
-
|
|
88
|
+
const server = new McpServer({ name: "rooms", version: "1.0.0" });
|
|
89
|
+
events.serve(server);
|
|
79
90
|
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
said.emit({ room: "lobby", text: "hello" });
|
|
92
|
+
```
|
|
82
93
|
|
|
83
|
-
A
|
|
94
|
+
A client subscribes and iterates:
|
|
84
95
|
|
|
85
96
|
```ts
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
});
|
|
97
|
+
const subscription = await apps.rooms.ext.events.subscribe("room.said", { room: "lobby" });
|
|
98
|
+
for await (const { data } of subscription) console.log(data.text);
|
|
89
99
|
```
|
|
90
100
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
</details>
|
|
101
|
+
The client is pushed each event on a stream where the server offers one and polls otherwise. It reconnects by itself and resumes from its cursor. Emitted events are kept in the server's memory, so after a restart the client's `onGap` is called: read the current state again.
|
|
94
102
|
|
|
95
|
-
|
|
96
|
-
<summary><h3>Read a resource</h3></summary>
|
|
103
|
+
To hand a page its state and then its changes, a tool returns the state together with `said.cursor()`, read in the same synchronous run, and the page subscribes from that cursor: it hears every change after the state, and none twice. Occurrences emitted one after another in one run reach each subscriber in that order with nothing of the same type between them, so a group of changes is emitted together or sent as one occurrence holding a list.
|
|
97
104
|
|
|
98
|
-
A
|
|
105
|
+
A source that keeps its own history is read through a check function instead. Its cursor is the source's own, so a client resumes across restarts with nothing skipped. Polls are answered by it, streams ask it every second, and the type can still `emit` to push at once:
|
|
99
106
|
|
|
100
107
|
```ts
|
|
101
|
-
|
|
108
|
+
events.event("email.received", {
|
|
109
|
+
inputSchema: z.object({ from: z.string() }),
|
|
110
|
+
payloadSchema: z.object({ subject: z.string() }),
|
|
111
|
+
check: async (cursor, { from }) => {
|
|
112
|
+
if (cursor === null) return { events: [], cursor: await mailbox.head() };
|
|
113
|
+
const { messages, head } = await mailbox.since(cursor, from);
|
|
114
|
+
return { events: messages.map(m => ({ eventId: m.id, data: { subject: m.subject } })), cursor: head };
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
```
|
|
102
118
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
An event type may also say who may subscribe, and hear when subscriptions begin and end:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const said = events.event("room.said", {
|
|
123
|
+
// ...
|
|
124
|
+
authorize: ({ room }, context) => mayRead(getContext(context).principal, room),
|
|
125
|
+
onSubscribe: ({ subscriptionId, arguments: { room } }) => {
|
|
126
|
+
listeners.set(subscriptionId, upstream.join(room, text => said.emit({ room, text }, { subscriptionId })));
|
|
127
|
+
},
|
|
128
|
+
onUnsubscribe: ({ subscriptionId }) => listeners.get(subscriptionId)?.leave(),
|
|
106
129
|
});
|
|
130
|
+
|
|
131
|
+
said.terminate(subscriptionId); // terminates one subscription; said.terminate() terminates them all
|
|
132
|
+
said.remove(); // stops offering the type
|
|
107
133
|
```
|
|
108
134
|
|
|
109
|
-
`
|
|
135
|
+
A refused subscription is answered Forbidden, and access is checked again at each poll and heartbeat. A subscription begins when its stream opens or its first poll arrives, and ends when its last stream closes or polls stop for a while. For a signed-in caller its `id` is the same for the same user, client, agent, scopes, event type and arguments, so what is emitted to it while its client reconnects is still delivered. A caller without an identity gets a new id for each stream, and its polls share one lease per arguments with every such caller, to which nothing is emitted alone. Each type keeps its last ten thousand events for ten minutes, polls are told to come back every second, a poll subscription ends a minute after its last poll, and subscriptions are limited to ten thousand in all and a thousand per caller. Names follow the design sketch.
|
|
110
136
|
|
|
111
|
-
|
|
137
|
+
Poll, push and webhook delivery are here, with check functions, targeted emits, subscription hooks, authorization, ending subscriptions, limits, paged listing and removing event types. Typed event names are not. Clients are not told when the event types change: they list them again.
|
|
112
138
|
|
|
113
|
-
|
|
139
|
+
### Webhook delivery
|
|
114
140
|
|
|
115
|
-
|
|
141
|
+
A server delivers by webhook too when `createEvents` is given the sketch's `webhookTtl`, the longest lifetime it grants a webhook subscription. Nothing else changes: `emit` reaches webhook subscribers as it does the others. A type with a check function is offered by poll and push only, since webhook delivery sends what is emitted.
|
|
116
142
|
|
|
117
143
|
```ts
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
server.registerTool("whoami", {}, async ctx => {
|
|
121
|
-
const { principal } = getContext(ctx.http);
|
|
122
|
-
if (!principal) throw new Error("Sign in first.");
|
|
123
|
-
principal.claims.email; // standard OpenID claims are typed: string | undefined
|
|
124
|
-
return { content: [{ type: "text", text: `${principal.subject} at ${principal.issuer}` }] };
|
|
125
|
-
});
|
|
144
|
+
const events = createEvents({ webhookTtl: 30 * 60_000 });
|
|
126
145
|
```
|
|
146
|
+
|
|
147
|
+
The SDK keeps each subscription, checks that its callback wants deliveries before sending any, signs each one per [Standard Webhooks](https://www.standardwebhooks.com/), retries failures, and drops a subscription its client stops refreshing. Only an authenticated caller can subscribe, and only an `https` callback at a public address is called. A type's `authorize`, hooks, `terminate`, `remove` and the limits of `createEvents` apply to webhook subscriptions as to the others, and access is checked again every thirty seconds, at each heartbeat. Subscriptions are kept in memory, so after a restart each comes back when its client next refreshes it.
|
|
148
|
+
|
|
149
|
+
Every subscription expires unless its client refreshes it: one that never expires would need storage the server does not have. On Holon, an app that delivers webhooks leaves `egress` undeclared in `holon.yaml`, since declared hosts are the only ones it can reach.
|
|
150
|
+
|
|
151
|
+
Subscribing by webhook is for clients that can be reached at an `https` URL. This client does not subscribe by webhook yet: a Holon app cannot serve the route a receiver needs, so it subscribes by push or poll.
|
|
152
|
+
|
|
153
|
+
## Community
|
|
154
|
+
|
|
155
|
+
Ask questions and share what you're building on the [Holon Discord](https://discord.gg/jXExyBdy).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Standard OpenID Connect address claims. */
|
|
2
|
+
export interface AddressClaims {
|
|
3
|
+
formatted?: string;
|
|
4
|
+
street_address?: string;
|
|
5
|
+
locality?: string;
|
|
6
|
+
region?: string;
|
|
7
|
+
postal_code?: string;
|
|
8
|
+
country?: string;
|
|
9
|
+
[claim: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
/** Standard OpenID Connect claims. Holon drops one whose value has the wrong type; other claims pass through as JSON. */
|
|
12
|
+
export interface IdentityClaims {
|
|
13
|
+
name?: string;
|
|
14
|
+
given_name?: string;
|
|
15
|
+
family_name?: string;
|
|
16
|
+
middle_name?: string;
|
|
17
|
+
nickname?: string;
|
|
18
|
+
preferred_username?: string;
|
|
19
|
+
profile?: string;
|
|
20
|
+
picture?: string;
|
|
21
|
+
website?: string;
|
|
22
|
+
email?: string;
|
|
23
|
+
email_verified?: boolean;
|
|
24
|
+
gender?: string;
|
|
25
|
+
birthdate?: string;
|
|
26
|
+
zoneinfo?: string;
|
|
27
|
+
locale?: string;
|
|
28
|
+
phone_number?: string;
|
|
29
|
+
phone_number_verified?: boolean;
|
|
30
|
+
address?: AddressClaims;
|
|
31
|
+
updated_at?: number;
|
|
32
|
+
[claim: string]: unknown;
|
|
33
|
+
}
|
|
34
|
+
/** The user a request acts for, as Holon admitted it. */
|
|
35
|
+
export interface Principal {
|
|
36
|
+
issuer: string;
|
|
37
|
+
subject: string;
|
|
38
|
+
clientId: string;
|
|
39
|
+
scopes: string[];
|
|
40
|
+
claims: IdentityClaims;
|
|
41
|
+
actor?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
/** The caller of the current MCP request. principal is null for anonymous requests. */
|
|
44
|
+
export interface RequestContext {
|
|
45
|
+
principal: Principal | null;
|
|
46
|
+
}
|
|
47
|
+
/** Read the caller from the context an MCP server receives: a tool callback's ctx.http, or the McpRequestContext of a createMcpHandler factory. */
|
|
48
|
+
export declare function getContext(context?: {
|
|
49
|
+
authInfo?: {
|
|
50
|
+
clientId: string;
|
|
51
|
+
scopes: string[];
|
|
52
|
+
extra?: Record<string, unknown>;
|
|
53
|
+
};
|
|
54
|
+
}): RequestContext;
|
|
55
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IACxH,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AACD,yHAAyH;AACzH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClG,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAClG,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAClG,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IACrG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AACD,yDAAyD;AACzD,MAAM,WAAW,SAAS;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE;AAC3J,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAAG,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;CAAE;AAM/D,mJAAmJ;AACnJ,wBAAgB,UAAU,CAAC,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAAO,GAAG,cAAc,CAK/I"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Read the caller from the context an MCP server receives: a tool callback's ctx.http, or the McpRequestContext of a createMcpHandler factory. */
|
|
2
|
+
export function getContext(context = {}) {
|
|
3
|
+
const { authInfo } = context;
|
|
4
|
+
const { iss, sub, claims, act } = (authInfo?.extra ?? {});
|
|
5
|
+
if (!authInfo || typeof iss !== "string" || typeof sub !== "string")
|
|
6
|
+
return { principal: null };
|
|
7
|
+
return { principal: { issuer: iss, subject: sub, clientId: authInfo.clientId, scopes: authInfo.scopes, claims: claims ?? {}, ...(act && { actor: act }) } };
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAsBA,mJAAmJ;AACnJ,MAAM,UAAU,UAAU,CAAC,OAAO,GAA2F,EAAE;IAC7H,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAa,CAAC;IACtE,IAAI,CAAC,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAChG,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAC9J,CAAC"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type { AuthInfo, JSONRPCErrorResponse, McpServer, Server, StandardSchemaWithJSON } from "@modelcontextprotocol/server";
|
|
2
|
+
import { type WebhookOptions } from "./webhooks.js";
|
|
3
|
+
export type { WebhookOptions } from "./webhooks.js";
|
|
4
|
+
/** The request a subscription came in, as Holon admitted it: read its caller with getContext. */
|
|
5
|
+
export type SubscriptionContext = {
|
|
6
|
+
authInfo?: AuthInfo | undefined;
|
|
7
|
+
} | undefined;
|
|
8
|
+
/** How a subscription receives its events. */
|
|
9
|
+
export type DeliveryModeName = "poll" | "push" | (string & {});
|
|
10
|
+
/** A JSON-RPC error, as a subscription that is terminated or fails is told it. */
|
|
11
|
+
export type EventError = JSONRPCErrorResponse["error"];
|
|
12
|
+
/** A subscription as it begins: who asked, for what, and by which delivery mode. */
|
|
13
|
+
export interface Subscription<A> {
|
|
14
|
+
/**
|
|
15
|
+
* The sketch's subscription_id: names the subscription to `emit` and `terminate`. For a caller with an identity it
|
|
16
|
+
* is the same for the same caller, event type and arguments, so it survives a reconnect and a poll lease that lapses. The caller is the user, the
|
|
17
|
+
* client acting for them, the agent acting for the user and the token's scopes, as Holon admitted them; two streams
|
|
18
|
+
* with the same id both receive what is emitted to it. A caller without a subject has no identity: each of its
|
|
19
|
+
* streams has an id of its own, which ends with the stream, and its polls share one lease per arguments with every
|
|
20
|
+
* such caller, to which nothing is emitted alone.
|
|
21
|
+
*/
|
|
22
|
+
readonly subscriptionId: string;
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly delivery: DeliveryModeName;
|
|
25
|
+
readonly arguments: A;
|
|
26
|
+
readonly context: SubscriptionContext;
|
|
27
|
+
}
|
|
28
|
+
/** An occurrence as subscriptions receive it: the sketch's EventOccurrence. `cursor` is the position after it. */
|
|
29
|
+
export interface EventOccurrence<D = unknown> {
|
|
30
|
+
eventId: string;
|
|
31
|
+
name: string;
|
|
32
|
+
/** When it happened, in ISO 8601. */
|
|
33
|
+
timestamp: string;
|
|
34
|
+
data: D;
|
|
35
|
+
cursor?: string | null;
|
|
36
|
+
_meta?: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* What happened after a cursor, as a check function finds it: the sketch's EventResult. Each event is an
|
|
40
|
+
* EventOccurrence whose name is the type's, and whose `eventId` (the source's own, so a client drops one it has seen)
|
|
41
|
+
* and `timestamp` are made up when not given. An event's `cursor`, the position just after it, lets a batch be cut
|
|
42
|
+
* short; without it a batch is delivered whole.
|
|
43
|
+
*/
|
|
44
|
+
export interface EventResult<D> {
|
|
45
|
+
/**
|
|
46
|
+
* Empty when the cursor was null: a null cursor asks only for the current position. A source without positions
|
|
47
|
+
* answers with a null cursor, is asked with null each time, and answers each time with what is new.
|
|
48
|
+
*/
|
|
49
|
+
events: Array<Omit<EventOccurrence<D>, "name" | "eventId" | "timestamp" | "cursor"> & {
|
|
50
|
+
eventId?: string;
|
|
51
|
+
timestamp?: string;
|
|
52
|
+
cursor?: string;
|
|
53
|
+
}>;
|
|
54
|
+
/** The position after these events, or null when the source cannot be resumed from a position. */
|
|
55
|
+
cursor: string | null;
|
|
56
|
+
/** Events between the cursor and these were skipped, for instance because the source no longer keeps them. */
|
|
57
|
+
truncated?: boolean;
|
|
58
|
+
/** More events are ready at once after this batch. */
|
|
59
|
+
hasMore?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** An event type: the arguments a subscription gives, and the data each occurrence carries. */
|
|
62
|
+
export interface EventDefinition<A, D> {
|
|
63
|
+
description?: string;
|
|
64
|
+
/** The arguments of a subscription. A request whose arguments do not match is refused. */
|
|
65
|
+
inputSchema: StandardSchemaWithJSON<unknown, A>;
|
|
66
|
+
/** The data of each occurrence, as subscriptions receive it. */
|
|
67
|
+
payloadSchema: StandardSchemaWithJSON;
|
|
68
|
+
/** Listed with the event type, as `_meta` is on a tool. */
|
|
69
|
+
_meta?: Record<string, unknown>;
|
|
70
|
+
/**
|
|
71
|
+
* Whether a subscription with these arguments receives an emitted event. Without it, every subscription does. When
|
|
72
|
+
* it or `transform` throws, or `transform` returns what cannot be sent as JSON, that event is skipped for that
|
|
73
|
+
* subscription: its cursor moves past it, a stream is told once with `notifications/events/error`, and the failure
|
|
74
|
+
* is logged.
|
|
75
|
+
*/
|
|
76
|
+
match?: (data: D, args: A, context: SubscriptionContext) => boolean;
|
|
77
|
+
/** The data a subscription with these arguments receives of an emitted event. Without it, the data as emitted. */
|
|
78
|
+
transform?: (data: D, args: A, context: SubscriptionContext) => unknown;
|
|
79
|
+
/**
|
|
80
|
+
* What happened after a cursor, for a source that keeps its own history: polls are answered by it, and streams ask
|
|
81
|
+
* it every second. The cursor is the source's own, so it outlives the process. A null cursor asks for the
|
|
82
|
+
* current position. The function filters and shapes for the arguments itself; `match` and `transform` apply only to
|
|
83
|
+
* what is emitted. Without it, emitted events are kept in memory and polls and streams are served from there.
|
|
84
|
+
*/
|
|
85
|
+
check?: (cursor: string | null, args: A, context: SubscriptionContext) => EventResult<D> | Promise<EventResult<D>>;
|
|
86
|
+
/** The delivery modes this event type offers. Every mode served unless given, except webhook for a type with a check function, which webhook delivery does not read. */
|
|
87
|
+
delivery?: DeliveryModeName[];
|
|
88
|
+
/**
|
|
89
|
+
* Whether the caller may subscribe with these arguments. A subscription is refused with Forbidden when it may not,
|
|
90
|
+
* and one already open is ended when it no longer may: each poll asks, and a stream asks at each heartbeat. A
|
|
91
|
+
* refused poll ends its lease at once.
|
|
92
|
+
*/
|
|
93
|
+
authorize?: (args: A, context: SubscriptionContext) => boolean | Promise<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* The sketch's on_subscribe: called when a subscription begins, to set up what its events come from. A
|
|
96
|
+
* subscription held by two streams at once is set up once. A server that restarts calls it again on the next poll
|
|
97
|
+
* or stream, with the same id. A subscription refused by the limits never reaches it.
|
|
98
|
+
*/
|
|
99
|
+
onSubscribe?: (subscription: Subscription<A>) => void | Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* The sketch's on_unsubscribe: called when a subscription that `onSubscribe` set up ends: its last push stream
|
|
102
|
+
* closes, its poll lease lapses because polls stopped, or the app terminates it.
|
|
103
|
+
*/
|
|
104
|
+
onUnsubscribe?: (subscription: Subscription<A>) => void | Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
/** Emits occurrences of one event type to the subscriptions they match, and ends its subscriptions. */
|
|
107
|
+
export interface Emitter<D> {
|
|
108
|
+
/**
|
|
109
|
+
* `eventId` lets a client drop an occurrence it has seen. Give the source's own id when it has one. With
|
|
110
|
+
* `subscriptionId`, the sketch's targeted emit, the occurrence goes to that subscription alone, whatever its arguments; it is kept like any
|
|
111
|
+
* other, so a subscription that reconnects or polls again from its cursor still has it, or is told of a gap. An
|
|
112
|
+
* event type with a check function pushes what it emits to open streams at once and does not keep it: polls and
|
|
113
|
+
* reconnecting streams learn of it from the check function, and one emitted to a subscription that does not get it
|
|
114
|
+
* on a stream is lost, so that subscription's next poll or stream is told of a gap.
|
|
115
|
+
*
|
|
116
|
+
* Emitting is synchronous. Occurrences emitted one after another in the same synchronous run reach each
|
|
117
|
+
* subscription in that order, with no other occurrence of this type between them, whether polled or pushed. So a
|
|
118
|
+
* group of changes that nothing may come between is either emitted in one run or sent as one occurrence holding a
|
|
119
|
+
* list. A subscription skips part of a group only when it is told of a gap: the group outgrew the events kept, or
|
|
120
|
+
* the subscription fell behind them. For a type with a check function the order holds among what is emitted, but
|
|
121
|
+
* not between what is emitted and what the check function finds, which may arrive later or again.
|
|
122
|
+
*
|
|
123
|
+
* The data is serialised when it is emitted, so data that cannot be sent as JSON throws here, before anything is
|
|
124
|
+
* kept or sent.
|
|
125
|
+
*/
|
|
126
|
+
emit(data: D, options?: {
|
|
127
|
+
eventId?: string;
|
|
128
|
+
timestamp?: string;
|
|
129
|
+
subscriptionId?: string;
|
|
130
|
+
}): void;
|
|
131
|
+
/**
|
|
132
|
+
* The position after the last occurrence emitted, for a type without a check function. Return it with the state
|
|
133
|
+
* a tool reads, in the same synchronous run, and a client that subscribes from it hears every change after that
|
|
134
|
+
* state and none before. A type with a check function has no such position here: its cursor is the source's own,
|
|
135
|
+
* so read the source's head instead. This throws for such a type.
|
|
136
|
+
*/
|
|
137
|
+
cursor(): string;
|
|
138
|
+
/**
|
|
139
|
+
* Terminates one subscription, or all of this type's: a stream is sent `notifications/events/terminated` with
|
|
140
|
+
* `error` and closed, and the next poll is answered with it. Forbidden unless given.
|
|
141
|
+
*/
|
|
142
|
+
terminate(subscriptionId?: string, error?: EventError): void;
|
|
143
|
+
/**
|
|
144
|
+
* Stops offering this event type: its subscriptions end with NotFound.
|
|
145
|
+
*/
|
|
146
|
+
remove(): void;
|
|
147
|
+
}
|
|
148
|
+
export interface EventsOptions {
|
|
149
|
+
/**
|
|
150
|
+
* The sketch's webhook_ttl, which turns webhook delivery on: the longest lifetime granted to a webhook
|
|
151
|
+
* subscription, in milliseconds. A client's suggestion is held to it, and every grant expires. Without it, webhook
|
|
152
|
+
* delivery is not offered.
|
|
153
|
+
*/
|
|
154
|
+
webhookTtl?: number;
|
|
155
|
+
/** For tests of webhook delivery. */
|
|
156
|
+
webhook?: WebhookOptions;
|
|
157
|
+
}
|
|
158
|
+
/** A delivery mode besides poll and push: webhook. It registers its requests on each server and is listed by events/list. Not for applications. */
|
|
159
|
+
export interface DeliveryMode {
|
|
160
|
+
readonly name: string;
|
|
161
|
+
serve(server: object, internals: Internals): void;
|
|
162
|
+
}
|
|
163
|
+
/** The event types of a process, served by each MCP server it creates. */
|
|
164
|
+
export interface Events {
|
|
165
|
+
/** Declares an event type. Emit its occurrences with the returned emitter. */
|
|
166
|
+
event<A, D>(name: string, definition: EventDefinition<A, D>): Emitter<D>;
|
|
167
|
+
/** Serves events/list, events/poll and events/stream on an McpServer or a Server, and declares the extension. */
|
|
168
|
+
serve(server: McpServer | Server): void;
|
|
169
|
+
/** What a delivery mode works with. Not for applications. */
|
|
170
|
+
readonly [INTERNALS]: Internals;
|
|
171
|
+
}
|
|
172
|
+
/** An emitted event: kept, at a sequence, for a type without a check function; pushed only, for one with. */
|
|
173
|
+
export interface Kept {
|
|
174
|
+
sequence?: number;
|
|
175
|
+
at?: number;
|
|
176
|
+
target?: string | undefined;
|
|
177
|
+
occurrence: EventOccurrence;
|
|
178
|
+
}
|
|
179
|
+
/** What a subscription is owed after a cursor. */
|
|
180
|
+
export interface Owed {
|
|
181
|
+
events: EventOccurrence[];
|
|
182
|
+
/** Events that could not be shaped for it, and were skipped. */
|
|
183
|
+
failures?: EventError[];
|
|
184
|
+
/** Where delivery starts. */
|
|
185
|
+
start: string | null;
|
|
186
|
+
cursor: string | null;
|
|
187
|
+
truncated: boolean;
|
|
188
|
+
hasMore: boolean;
|
|
189
|
+
}
|
|
190
|
+
/** A subscription as a delivery mode holds it. */
|
|
191
|
+
export interface Held {
|
|
192
|
+
readonly id: string;
|
|
193
|
+
readonly name: string;
|
|
194
|
+
readonly delivery: DeliveryModeName;
|
|
195
|
+
readonly arguments: unknown;
|
|
196
|
+
readonly context: SubscriptionContext;
|
|
197
|
+
/** Nothing is emitted to it alone: a poll lease shared by callers without an identity. */
|
|
198
|
+
untargetable?: boolean;
|
|
199
|
+
/** Called when the app ends the subscription. */
|
|
200
|
+
readonly end: (error: EventError) => void;
|
|
201
|
+
/** Says the hold is over. */
|
|
202
|
+
close(): void;
|
|
203
|
+
}
|
|
204
|
+
/** The subscription a request asks for, checked. */
|
|
205
|
+
export interface Requested {
|
|
206
|
+
id: string;
|
|
207
|
+
lease: string;
|
|
208
|
+
arguments: unknown;
|
|
209
|
+
context: SubscriptionContext;
|
|
210
|
+
untargetable?: boolean;
|
|
211
|
+
}
|
|
212
|
+
/** A declared event type, as the delivery modes see it. */
|
|
213
|
+
export interface EventTypeState {
|
|
214
|
+
readonly name: string;
|
|
215
|
+
readonly delivery: DeliveryModeName[];
|
|
216
|
+
readonly interval: number;
|
|
217
|
+
readonly check?: EventDefinition<unknown, unknown>["check"];
|
|
218
|
+
/** Whether the caller may hold the subscription, which a mode that holds subscriptions long asks again. */
|
|
219
|
+
authorize?(args: unknown, context: SubscriptionContext): boolean | Promise<boolean>;
|
|
220
|
+
/** Told each event as it is emitted: a push stream is one, and a delivery mode adds its own. */
|
|
221
|
+
readonly sinks: Set<(kept: Kept) => void>;
|
|
222
|
+
/** The subscriptions held by every mode, by id. */
|
|
223
|
+
readonly subscriptions: Map<string, {
|
|
224
|
+
held: Set<Held>;
|
|
225
|
+
ready: Promise<unknown>;
|
|
226
|
+
}>;
|
|
227
|
+
}
|
|
228
|
+
/** What a delivery mode works with. */
|
|
229
|
+
export interface Internals {
|
|
230
|
+
readonly types: Map<string, EventTypeState>;
|
|
231
|
+
/** Checks a request, names its event type and the subscription's id. */
|
|
232
|
+
readonly subscription: (request: Record<string, unknown>, context: SubscriptionContext, delivery?: DeliveryModeName) => Promise<{
|
|
233
|
+
type: EventTypeState;
|
|
234
|
+
subscription: Requested;
|
|
235
|
+
}>;
|
|
236
|
+
/** Begins holding a subscription. */
|
|
237
|
+
readonly open: (type: EventTypeState, subscription: {
|
|
238
|
+
id: string;
|
|
239
|
+
delivery: DeliveryModeName;
|
|
240
|
+
arguments: unknown;
|
|
241
|
+
context: SubscriptionContext;
|
|
242
|
+
}, end: (error: EventError) => void) => Promise<Held>;
|
|
243
|
+
/** What a subscription is owed after a cursor. */
|
|
244
|
+
readonly read: (type: EventTypeState, subscription: Pick<Held, "id" | "arguments" | "context" | "untargetable">, cursor: string | null | undefined, options?: {
|
|
245
|
+
maxAgeMs?: number;
|
|
246
|
+
maxEvents?: number;
|
|
247
|
+
}) => Owed | Promise<Owed>;
|
|
248
|
+
/** What a subscription is owed of the events emitted. */
|
|
249
|
+
readonly since: (type: EventTypeState, subscription: Pick<Held, "id" | "arguments" | "context" | "untargetable">, cursor: string | null | undefined, maxAgeMs?: number, limit?: number) => Owed;
|
|
250
|
+
/** An emitted event as one subscription receives it, or nothing when it is not for it. */
|
|
251
|
+
readonly shape: (type: EventTypeState, kept: Kept, subscription: Pick<Held, "id" | "arguments" | "context" | "untargetable">, failed?: (error: EventError) => void) => EventOccurrence | undefined;
|
|
252
|
+
/** A type's current cursor. */
|
|
253
|
+
readonly position: (type: EventTypeState, sequence?: number) => string;
|
|
254
|
+
}
|
|
255
|
+
/** The identifier a server declares the Events extension under, in capabilities.extensions. */
|
|
256
|
+
export declare const EVENTS_EXTENSION = "io.modelcontextprotocol/events";
|
|
257
|
+
/** Reaches what a delivery mode needs of the events it serves. Not for applications. */
|
|
258
|
+
export declare const INTERNALS: unique symbol;
|
|
259
|
+
/**
|
|
260
|
+
* Event types a process emits and the MCP servers it creates serve, in the poll and push delivery modes of MCP Events,
|
|
261
|
+
* the draft extension of the Triggers & Events Working Group. Each type keeps the last ten thousand events it emits,
|
|
262
|
+
* for ten minutes, for polls and for streams that reconnect: those cursors last as long as the process, and after a
|
|
263
|
+
* restart a client is told that events were skipped. A type with a check function uses its source's cursors instead,
|
|
264
|
+
* which outlive the process. A type is asked again, and a poll told to come back, every second. A stream hears from
|
|
265
|
+
* the server every thirty seconds.
|
|
266
|
+
*/
|
|
267
|
+
export declare function createEvents({ webhookTtl, webhook }?: EventsOptions): Events;
|
|
268
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/ext/events.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC9H,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE9D,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,iGAAiG;AACjG,MAAM,MAAM,mBAAmB,GAAG;IAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,CAAC;AAClF,8CAA8C;AAC9C,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAC/D,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;AACvD,oFAAoF;AACpF,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B;;;;;;;OAOG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;CACvC;AACD,kHAAkH;AAClH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AACD;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B;;;OAGG;IACH,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjJ,kGAAkG;IAClG,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,8GAA8G;IAC9G,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AACD,+FAA+F;AAC/F,MAAM,WAAW,eAAe,CAAC,CAAC,EAAE,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,WAAW,EAAE,sBAAsB,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAChD,gEAAgE;IAChE,aAAa,EAAE,sBAAsB,CAAC;IACtC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC;IACpE,kHAAkH;IAClH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC;IACxE;;;;;OAKG;IACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACnH,wKAAwK;IACxK,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE;AACD,uGAAuG;AACvG,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjG;;;;;OAKG;IACH,MAAM,IAAI,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7D;;OAEG;IACH,MAAM,IAAI,IAAI,CAAC;CAChB;AACD,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AACD,mJAAmJ;AACnJ,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CACnD;AACD,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,8EAA8E;IAC9E,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzE,iHAAiH;IACjH,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC;IACxC,6DAA6D;IAC7D,QAAQ,CAAC,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CACjC;AAED,6GAA6G;AAC7G,MAAM,WAAW,IAAI;IAAG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,UAAU,EAAE,eAAe,CAAA;CAAE;AAClH,kDAAkD;AAClD,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;IACxB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AACD,kDAAkD;AAClD,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,0FAA0F;IAC1F,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,6BAA6B;IAC7B,KAAK,IAAI,IAAI,CAAC;CACf;AACD,oDAAoD;AACpD,MAAM,WAAW,SAAS;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE;AAClI,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC;IAC5D,2GAA2G;IAC3G,SAAS,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,gGAAgG;IAChG,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC;IAC1C,mDAAmD;IACnD,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;CACnF;AACD,uCAAuC;AACvC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,YAAY,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACnL,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,gBAAgB,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,mBAAmB,CAAA;KAAE,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrM,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,GAAG,cAAc,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjO,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,GAAG,cAAc,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChM,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,GAAG,cAAc,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,KAAK,eAAe,GAAG,SAAS,CAAC;IACnM,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACxE;AAED,+FAA+F;AAC/F,eAAO,MAAM,gBAAgB,mCAAmC,CAAC;AACjE,wFAAwF;AACxF,eAAO,MAAM,SAAS,EAAE,OAAO,MAAgD,CAAC;AA2FhF;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,GAAE,aAAkB,GAAG,MAAM,CA+dhF"}
|