@gjermundgaraba/effect-actions 0.16.0 → 0.18.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 +3 -1
- package/dist/Action.d.mts +3 -5
- package/dist/Action.mjs +3 -1
- package/dist/ActionCli.d.mts +31 -42
- package/dist/ActionCli.mjs +6 -16
- package/dist/ActionHttp.d.mts +12 -8
- package/dist/ActionHttp.mjs +3 -1
- package/dist/ActionMcp.d.mts +1 -1
- package/dist/ActionMcp.mjs +4 -1
- package/dist/ActionRpc.d.mts +5 -3
- package/dist/ActionRpc.mjs +2 -1
- package/dist/ActionToolkit.d.mts +3 -2
- package/dist/ActionToolkit.mjs +3 -1
- package/dist/Authentication.d.mts +1 -1
- package/dist/Authentication.mjs +1 -1
- package/dist/authentication/provider.d.mts +2 -2
- package/dist/authentication/refusal.mjs +1 -1
- package/dist/cli/commands.d.mts +4 -3
- package/dist/cli/commands.mjs +6 -5
- package/dist/contract/ast.mjs +10 -0
- package/dist/contract/call.d.mts +1 -1
- package/dist/contract/caller.d.mts +9 -0
- package/dist/contract/caller.mjs +12 -0
- package/dist/contract/{rules.d.mts → declared.d.mts} +6 -10
- package/dist/contract/declared.mjs +42 -0
- package/dist/contract/hints.mjs +14 -0
- package/dist/contract/implementation.d.mts +4 -3
- package/dist/contract/implementation.mjs +4 -8
- package/dist/contract/names.mjs +25 -0
- package/dist/contract/status.mjs +18 -0
- package/dist/http/client.d.mts +19 -9
- package/dist/http/client.mjs +6 -1
- package/dist/mcp/client.d.mts +52 -12
- package/dist/mcp/client.mjs +62 -19
- package/dist/mcp/protocol.mjs +1 -1
- package/docs/Action.md +17 -3
- package/docs/ActionCli-failures.md +10 -9
- package/docs/ActionCli.md +22 -21
- package/docs/ActionHttp-failures.md +6 -0
- package/docs/ActionHttp.md +9 -4
- package/docs/ActionMcp.md +3 -3
- package/docs/ActionToolkit.md +25 -2
- package/docs/Authentication-failures.md +1 -1
- package/docs/CONTEXT.md +2 -1
- package/docs/README.md +4 -4
- package/docs/Testing.md +3 -1
- package/examples/README.md +10 -2
- package/examples/assistant/README.md +24 -20
- package/examples/assistant/src/agent.ts +11 -7
- package/examples/assistant/src/cli.ts +2 -2
- package/examples/assistant/src/platform/tasks-file.ts +38 -0
- package/examples/assistant/src/tasks/store.ts +6 -38
- package/examples/assistant/src/toolkit.ts +11 -1
- package/examples/assistant/test/{tasks/store.test.ts → platform/tasks-file.test.ts} +2 -1
- package/examples/kitchen-sink/src/cli.ts +19 -21
- package/examples/mcp-tools/README.md +14 -11
- package/examples/mcp-tools/src/{printers/fake.ts → platform/fake-farm.ts} +2 -2
- package/examples/mcp-tools/src/platform/print-farm.ts +118 -0
- package/examples/mcp-tools/src/printers/farm.ts +6 -122
- package/examples/mcp-tools/src/server.ts +4 -4
- package/examples/mcp-tools/src/stdio.ts +4 -4
- package/examples/mcp-tools/test/printers/printers.test.ts +3 -3
- package/examples/mcp-tools/test/routes.test.ts +4 -4
- package/examples/notes-service/README.md +34 -2
- package/examples/notes-service/src/cli.ts +3 -9
- package/examples/notes-service/src/commands.ts +40 -36
- package/examples/notes-service/src/identity/authorize.ts +1 -0
- package/examples/notes-service/src/notes/Notes.ts +22 -5
- package/examples/notes-service/src/notes/handlers.ts +2 -2
- package/examples/notes-service/src/notes/store.ts +36 -6
- package/examples/notes-service/test/commands.test.ts +13 -19
- package/examples/notes-service/test/notes/idempotency.test.ts +132 -0
- package/examples/notes-service/test/routes.test.ts +40 -1
- package/package.json +5 -5
- package/dist/_virtual/_rolldown/runtime.mjs +0 -13
- package/dist/contract/rules.mjs +0 -100
package/README.md
CHANGED
|
@@ -72,7 +72,9 @@ implementation is also:
|
|
|
72
72
|
```ts
|
|
73
73
|
const { toolkit, layer } = ActionToolkit.make(greeting); // native Effect AI Toolkit and its handler layer
|
|
74
74
|
const cli = ActionCli.make(greeting, { name: "greetings" }); // greetings greet --name Ada
|
|
75
|
-
const remote = ActionCli.remoteCommand(Http, Greet, {
|
|
75
|
+
const remote = ActionCli.remoteCommand(Http, Greet, {
|
|
76
|
+
client: ActionHttp.client(Http, { baseUrl }),
|
|
77
|
+
}); // greet --name Ada, over HTTP
|
|
76
78
|
const local = Action.client(greeting); // the HTTP client's methods, in process
|
|
77
79
|
const rpc = ActionRpc.layer(ActionRpc.make([Greet]), greeting); // Effect RPC, on the protocol the host provides
|
|
78
80
|
```
|
package/dist/Action.d.mts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { Anyone } from "./contract/
|
|
1
|
+
import { Anyone } from "./contract/caller.mjs";
|
|
2
2
|
import { BuiltIn, BuiltIns, Forbidden, InvalidInput, Issue, Refusal, Unauthenticated } from "./contract/errors.mjs";
|
|
3
3
|
import { ActionOf, AnyImplementation, Authorize, BuildError, BuildServices, Holding, Implementation, Known, Member, Offered, OptionalUnless, Protected, RequestOf, SelectedOf, Served, Serving } from "./contract/implementation.mjs";
|
|
4
4
|
import { Call } from "./contract/call.mjs";
|
|
5
5
|
import { Image } from "./contract/media.mjs";
|
|
6
6
|
import { Context, Effect, Layer, Schema, Scope } from "effect";
|
|
7
|
-
|
|
8
|
-
export { Action, Any, AnyImplementation, Anyone, Authorize, BuildError, BuildServices, BuiltIn, Client, ClientOptions, Errors, Forbidden, Handler, Handlers, Image, Implementation, InvalidInput, Issue, Mcp, Options, Refusal, Unauthenticated, allowAll, byName, client, implement, layer, make };
|
|
9
|
-
}
|
|
7
|
+
//#region src/contract/Action.d.ts
|
|
10
8
|
type Codec = Schema.Codec<unknown, unknown, never, never>;
|
|
11
9
|
type Fields = {
|
|
12
10
|
readonly [key: string]: Codec;
|
|
@@ -213,4 +211,4 @@ export interface ClientOptions<A extends Any> {
|
|
|
213
211
|
*/
|
|
214
212
|
export declare function client<const Apps extends Served, const O extends ClientOptions<ActionOf<Member<Apps>>> = {}>(implementations: Apps, ...options: OptionalUnless<O, ClientOptions<ActionOf<Member<Apps>>> & O & NoInfer<Known<O, ClientOptions<Any>>>>): Effect.Effect<Client<Apps, Offered<O, ActionOf<Member<Apps>>>>, BuildError<Holding<Member<Apps>, SelectedOf<O, Apps>>, SelectedOf<O, Apps>>, BuildServices<Holding<Member<Apps>, SelectedOf<O, Apps>>, SelectedOf<O, Apps>> | Scope.Scope>;
|
|
215
213
|
//#endregion
|
|
216
|
-
export {
|
|
214
|
+
export { type AnyImplementation, Anyone, type Authorize, type BuildError, type BuildServices, BuiltIn, Forbidden, Image, type Implementation, InvalidInput, type Issue, Refusal, Unauthenticated };
|
package/dist/Action.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { Anyone } from "./contract/caller.mjs";
|
|
1
2
|
import { BuiltIn, Forbidden, InvalidInput, Refusal, Unauthenticated } from "./contract/errors.mjs";
|
|
2
|
-
import {
|
|
3
|
+
import { assertKnown, assertName, assertOnce } from "./contract/names.mjs";
|
|
4
|
+
import { assertOwnTags, errorList, projectedErrors } from "./contract/declared.mjs";
|
|
3
5
|
import { Implementation, builders, built, memoized, select, toList } from "./contract/implementation.mjs";
|
|
4
6
|
import { inputOf } from "./contract/call.mjs";
|
|
5
7
|
import { Image } from "./contract/media.mjs";
|
package/dist/ActionCli.d.mts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { Declaring } from "./contract/rules.mjs";
|
|
2
1
|
import { BuiltIn } from "./contract/errors.mjs";
|
|
3
2
|
import { ActionOf, BuildError, BuildServices, Holding, Known, Member, RequestOf, Selected, SelectedOf, Selection, Served } from "./contract/implementation.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { Any } from "./Action.mjs";
|
|
4
|
+
import { Declaring } from "./contract/declared.mjs";
|
|
6
5
|
import { Options, UserError } from "./cli/commands.mjs";
|
|
7
|
-
import { AnyHttp,
|
|
6
|
+
import { AnyHttp, Client } from "./http/client.mjs";
|
|
8
7
|
import "./ActionHttp.mjs";
|
|
9
|
-
import { Effect
|
|
10
|
-
import { HttpClient
|
|
11
|
-
import { Command } from "effect/cli";
|
|
8
|
+
import { Effect } from "effect";
|
|
9
|
+
import { HttpClient } from "effect/http";
|
|
10
|
+
import { CliError, Command } from "effect/cli";
|
|
12
11
|
//#region src/cli/ActionCli.d.ts
|
|
13
12
|
interface AnyBinding extends Declaring {
|
|
14
13
|
readonly actions: ReadonlyArray<Any>;
|
|
@@ -24,7 +23,7 @@ interface AnyBinding extends Declaring {
|
|
|
24
23
|
* `Effect.tapError(() => Console.error(…))`: a `UserError` wrapped around the result would
|
|
25
24
|
* replace its JSON.
|
|
26
25
|
*/
|
|
27
|
-
export declare const toUserError: (calls: AnyBinding | ReadonlyArray<Any>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, UserError<Exclude<E,
|
|
26
|
+
export declare const toUserError: (calls: AnyBinding | ReadonlyArray<Any>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, UserError<Exclude<E, CliError.CliError>> | Exclude<E, Exclude<E, CliError.CliError>>, R>;
|
|
28
27
|
/**
|
|
29
28
|
* An aggregate command of the actions `A`: its name, the actions that are its subcommands,
|
|
30
29
|
* and their options.
|
|
@@ -69,39 +68,28 @@ type Local<App, A extends Any> = Effect.Effect<A["success"]["Type"], A["error"][
|
|
|
69
68
|
* as JSON when it is not a struct. The flag of an array of strings or numbers is repeated for each value, a boolean
|
|
70
69
|
* field is a switch, `--no-<name>` sending `false` as a required one left out does, and a field's `description` is its flag's help. It needs what the authorization, its handler and its builder
|
|
71
70
|
* need; the host provides the identity. It prints the result on stdout; a failure is a
|
|
72
|
-
* `UserError`,
|
|
71
|
+
* `UserError`, or an Effect CLI error as it is, such as a builder's `CliError.UserError`, which
|
|
72
|
+
* `Command.run` prints on stderr. `remoteCommand` calls a server instead.
|
|
73
73
|
*/
|
|
74
|
-
export declare function command<const Apps extends Served, A extends ActionOf<Member<Apps>>, const O = {}>(implementations: Apps, action: A, options?: O & NoInfer<Options<A>> & NoInfer<Known<O, Options<Any>>>): Command.Command<string, never, {},
|
|
74
|
+
export declare function command<const Apps extends Served, A extends ActionOf<Member<Apps>>, const O = {}>(implementations: Apps, action: A, options?: O & NoInfer<Options<A>> & NoInfer<Known<O, Options<Any>>>): Command.Command<string, never, {}, Failing<Effect.Error<Local<Owning<Member<Apps>, A>, A>>>, Effect.Services<Local<Owning<Member<Apps>, A>, A>>>;
|
|
75
75
|
/**
|
|
76
76
|
* Project one action of an HTTP binding into a native Effect CLI command, derived as `command`
|
|
77
|
-
* derives it, that calls the action
|
|
78
|
-
* the
|
|
79
|
-
*
|
|
77
|
+
* derives it, that calls the action through `client`'s method and fails as the method does, or
|
|
78
|
+
* as the Effect building the client does. `client` is an Effect of the binding's client, such as
|
|
79
|
+
* `ActionHttp.client(Http, { baseUrl })`, run each time the command runs; omitted, it is
|
|
80
|
+
* `ActionHttp.client(binding)` on the host's `HttpClient`. It runs nothing locally.
|
|
80
81
|
*/
|
|
81
|
-
export declare function remoteCommand<const H extends AnyHttp, A extends H["actions"][number], const O = {}>(binding: H, action: A, options?: O & NoInfer<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
*/
|
|
88
|
-
readonly client?: Options$2;
|
|
89
|
-
};
|
|
90
|
-
/** A remote aggregate command's options, its actions `A`. */
|
|
91
|
-
export type RemoteOptions<A extends Any = Any> = Options$1<A> & {
|
|
92
|
-
/**
|
|
93
|
-
* Every subcommand's client options, as `ActionHttp.client` takes them: `baseUrl`, and
|
|
94
|
-
* `transformClient` for credentials. They reach this aggregate's requests alone. A URL or a
|
|
95
|
-
* token read from `Config` goes instead into the `HttpClient` provided on the command, with
|
|
96
|
-
* `Command.provideEffect(HttpClient.HttpClient, …)`: it is read when a command runs, so
|
|
97
|
-
* `--help` needs neither, and a command of your own in `subcommands` calls through it too.
|
|
98
|
-
* A required one that is not set fails that Effect with a `ConfigError`, which is no
|
|
99
|
-
* command's failure and prints as a crash line: map the read,
|
|
100
|
-
* `Effect.mapError((cause) => new CliError.UserError({ cause, userMessage: "TOKEN is not set" }))`.
|
|
101
|
-
*/
|
|
102
|
-
readonly client?: Options$2;
|
|
82
|
+
export declare function remoteCommand<const H extends AnyHttp, A extends H["actions"][number], const O = {}, C extends ClientOf<H> | undefined = undefined>(binding: H, action: A, options?: O & NoInfer<Options<A>> & NoInfer<Known<O, RemoteKeys<Options<Any>>>> & {
|
|
83
|
+
readonly client?: C;
|
|
84
|
+
}): Command.Command<string, never, {}, Failing<CallFailure<H, C, A>>, CallServices<C, A>>;
|
|
85
|
+
type ClientOf<H extends AnyHttp> = Effect.Effect<Client<H, unknown, unknown>, unknown, unknown>;
|
|
86
|
+
type RemoteKeys<Keys> = Keys & {
|
|
87
|
+
readonly client?: unknown;
|
|
103
88
|
};
|
|
104
|
-
type
|
|
89
|
+
type Failing<F> = UserError<Exclude<F, CliError.CliError>> | Extract<F, CliError.CliError>;
|
|
90
|
+
type Called<M, A extends Any> = A extends unknown ? A["name"] extends keyof M ? M[A["name"]] extends ((...input: never) => infer Call) ? Call : never : never : never;
|
|
91
|
+
type CallFailure<H extends AnyHttp, C, A extends Any> = C extends Effect.Effect<infer M, infer CE, unknown> ? CE | Effect.Error<Called<M, A>> : Effect.Error<Called<Client<H>, A>>;
|
|
92
|
+
type CallServices<C, A extends Any> = C extends Effect.Effect<infer M, unknown, infer CR> ? CR | Effect.Services<Called<M, A>> : HttpClient.HttpClient;
|
|
105
93
|
/**
|
|
106
94
|
* Project every implemented action as a subcommand of one aggregate command, each named after
|
|
107
95
|
* its action in kebab case and run in process. `commands` gives a subcommand the options
|
|
@@ -113,16 +101,17 @@ type HttpUserError<H extends AnyHttp, A extends Any> = UserError<A["error"][numb
|
|
|
113
101
|
*/
|
|
114
102
|
export declare function make<const Apps extends Served, const O extends Selection<ActionOf<Member<Apps>>> = {}, const Own extends Subcommands = []>(implementations: Apps, options: O & NoInfer<Options$1<ActionOf<Member<Apps>>>> & NoInfer<KnownOptions<O, Options$1, ActionOf<Member<Apps>>>> & {
|
|
115
103
|
readonly subcommands?: Own | undefined;
|
|
116
|
-
}): Command.Command<string, {}, {},
|
|
104
|
+
}): Command.Command<string, {}, {}, Failing<Effect.Error<Local<Holding<Member<Apps>, SelectedOf<O, Apps>>, SelectedOf<O, Apps>>>> | Command.Error<OwnCommand<Own>>, Effect.Services<Local<Holding<Member<Apps>, SelectedOf<O, Apps>>, SelectedOf<O, Apps>>> | Command.Services<OwnCommand<Own>>>;
|
|
117
105
|
/**
|
|
118
106
|
* Project every action of an HTTP binding as a subcommand of one aggregate command, derived as
|
|
119
|
-
* `make` derives it, each calling its action
|
|
120
|
-
*
|
|
121
|
-
*
|
|
107
|
+
* `make` derives it, each calling its action through `client`'s method, as `remoteCommand`
|
|
108
|
+
* does. `commands` gives one the options `command` takes; `subcommands` adds commands of your
|
|
109
|
+
* own, which call through the same client by yielding the Effect given as `client`.
|
|
122
110
|
*/
|
|
123
|
-
export declare function remote<const H extends AnyHttp, const O extends Selection<H["actions"][number]> = {}, const Own extends Subcommands = []>(binding: H, options: O & NoInfer<
|
|
111
|
+
export declare function remote<const H extends AnyHttp, const O extends Selection<H["actions"][number]> = {}, const Own extends Subcommands = [], C extends ClientOf<H> | undefined = undefined>(binding: H, options: O & NoInfer<Options$1<H["actions"][number]>> & NoInfer<KnownOptions<O, RemoteKeys<Options$1<Any>>, H["actions"][number]>> & {
|
|
112
|
+
readonly client?: C;
|
|
124
113
|
readonly subcommands?: Own | undefined;
|
|
125
|
-
}): Command.Command<string, {}, {},
|
|
114
|
+
}): Command.Command<string, {}, {}, Failing<CallFailure<H, C, Selected<O, H["actions"][number]>>> | Command.Error<OwnCommand<Own>>, CallServices<C, Selected<O, H["actions"][number]>> | Command.Services<OwnCommand<Own>>>;
|
|
126
115
|
/**
|
|
127
116
|
* A program whose stdout carries only its results, such as a CLI feeding scripts or an MCP
|
|
128
117
|
* subprocess, applied last, before `NodeRuntime.runMain`: the default logger of every layer
|
package/dist/ActionCli.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { assertDistinct, assertKnown
|
|
1
|
+
import { assertDistinct, assertKnown } from "./contract/names.mjs";
|
|
2
|
+
import { bindingErrors, projectedErrors } from "./contract/declared.mjs";
|
|
2
3
|
import { Implementation, acquire, assertHeld, select, toList } from "./contract/implementation.mjs";
|
|
3
4
|
import { client } from "./ActionHttp.mjs";
|
|
4
5
|
import { command as command$1, failingAsDerived } from "./cli/commands.mjs";
|
|
@@ -16,7 +17,7 @@ import { Command } from "effect/cli";
|
|
|
16
17
|
* `Effect.tapError(() => Console.error(…))`: a `UserError` wrapped around the result would
|
|
17
18
|
* replace its JSON.
|
|
18
19
|
*/
|
|
19
|
-
const toUserError = (calls) => "actions" in calls ? failingAsDerived(calls.actions
|
|
20
|
+
const toUserError = (calls) => "actions" in calls ? failingAsDerived(calls.actions.flatMap((action) => bindingErrors(action, calls))) : failingAsDerived(calls.flatMap((action) => projectedErrors(action)));
|
|
20
21
|
const runWithBuildOfItsOwn = (app, action, input) => {
|
|
21
22
|
const thisActionOnly = Implementation.share([action], app);
|
|
22
23
|
return Effect.flatMap(acquire([thisActionOnly]), (bound) => {
|
|
@@ -36,7 +37,7 @@ const inProcess = (apps, action, options) => {
|
|
|
36
37
|
};
|
|
37
38
|
const overHttp = (binding, action, options, client$1) => {
|
|
38
39
|
if (!binding.actions.includes(action)) throw new Error(`Action "${action.name}" is not in this HTTP binding`);
|
|
39
|
-
return command$1(action, (input) => Effect.flatMap(client(binding
|
|
40
|
+
return command$1(action, (input) => Effect.flatMap(client$1 ?? client(binding), (methods) => {
|
|
40
41
|
const method = methods[action.name];
|
|
41
42
|
if (method === void 0) throw new Error(`No client method for ${action.name}`);
|
|
42
43
|
return method(input);
|
|
@@ -68,17 +69,12 @@ const checkedCommandsOf = (commands, actions) => {
|
|
|
68
69
|
* as JSON when it is not a struct. The flag of an array of strings or numbers is repeated for each value, a boolean
|
|
69
70
|
* field is a switch, `--no-<name>` sending `false` as a required one left out does, and a field's `description` is its flag's help. It needs what the authorization, its handler and its builder
|
|
70
71
|
* need; the host provides the identity. It prints the result on stdout; a failure is a
|
|
71
|
-
* `UserError`,
|
|
72
|
+
* `UserError`, or an Effect CLI error as it is, such as a builder's `CliError.UserError`, which
|
|
73
|
+
* `Command.run` prints on stderr. `remoteCommand` calls a server instead.
|
|
72
74
|
*/
|
|
73
75
|
function command(implementations, action, options) {
|
|
74
76
|
return inProcess(toList(implementations), action, options);
|
|
75
77
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Project one action of an HTTP binding into a native Effect CLI command, derived as `command`
|
|
78
|
-
* derives it, that calls the action over HTTP through its `ActionHttp.client` method, made with
|
|
79
|
-
* the `client` options on the host's `HttpClient`, and fails as the method does. It runs
|
|
80
|
-
* nothing locally.
|
|
81
|
-
*/
|
|
82
78
|
function remoteCommand(binding, action, options) {
|
|
83
79
|
const { client, ...syntax } = options ?? {};
|
|
84
80
|
return overHttp(binding, action, options === void 0 ? void 0 : syntax, client);
|
|
@@ -98,12 +94,6 @@ function make(implementations, options) {
|
|
|
98
94
|
const served = select(apps, options.actions);
|
|
99
95
|
return aggregateCommand(options.name, served.flatMap((app) => app.actions), commands, options.subcommands ?? [], (action, syntax) => inProcess(served, action, syntax));
|
|
100
96
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Project every action of an HTTP binding as a subcommand of one aggregate command, derived as
|
|
103
|
-
* `make` derives it, each calling its action over HTTP. `client` configures every derived
|
|
104
|
-
* subcommand's client; `commands` gives one the options `command` takes; `subcommands` adds
|
|
105
|
-
* commands of your own.
|
|
106
|
-
*/
|
|
107
97
|
function remote(binding, options) {
|
|
108
98
|
const listed = options.actions;
|
|
109
99
|
if (listed !== void 0) assertHeld("the binding does not hold it", listed, binding.actions);
|
package/dist/ActionHttp.d.mts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { Anyone
|
|
1
|
+
import { Anyone } from "./contract/caller.mjs";
|
|
2
2
|
import { BuiltIn, BuiltIns } from "./contract/errors.mjs";
|
|
3
3
|
import { BuildError, Holding, Known, Member, MiddlewareOf, Protected, Selected, Served, Serving } from "./contract/implementation.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { Any, Errors } from "./Action.mjs";
|
|
5
5
|
import { Any as Any$1, DescriptorOf, Identity, Matching, PublicOnly, RemoteRequest, Required, ServedProvider, ServerBuildServices, VerifierError } from "./authentication/provider.mjs";
|
|
6
|
+
import { Certain, ErrorsOf } from "./contract/declared.mjs";
|
|
6
7
|
import { AnyHttp, Client, MethodError, Options } from "./http/client.mjs";
|
|
7
8
|
import { Context, Effect, FileSystem, Layer, Path, Schema, Types } from "effect";
|
|
8
|
-
import { Etag, HttpClient, HttpPlatform, HttpRouter } from "effect/http";
|
|
9
|
+
import { Etag, HttpClient, HttpClientError, HttpPlatform, HttpRouter } from "effect/http";
|
|
9
10
|
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware } from "effect/http-api";
|
|
10
11
|
//#region src/http/ActionHttp.d.ts
|
|
11
12
|
/** What `fetchClient` takes: `client`'s options, and the `fetch` its calls send with. */
|
|
12
|
-
export interface FetchClientOptions extends Options {
|
|
13
|
+
export interface FetchClientOptions<E = HttpClientError.HttpClientError, R = never> extends Options<E, R> {
|
|
13
14
|
/**
|
|
14
15
|
* What each call sends with. Omitted: the global `fetch`, looked up on every call, so one
|
|
15
16
|
* installed after the client is built, such as a test's stub, is used.
|
|
@@ -115,18 +116,21 @@ export declare function layer<const H extends AnyHttp, const Apps extends Served
|
|
|
115
116
|
* `InvalidInput`, `Unauthenticated` or `Forbidden`), a native `HttpClientError` when the
|
|
116
117
|
* server could not be reached or answered with a status or body the contract does not
|
|
117
118
|
* declare, or a `SchemaError` when the success does not decode. An input that does not encode
|
|
118
|
-
* fails with `InvalidInput`, and nothing is sent.
|
|
119
|
+
* fails with `InvalidInput`, and nothing is sent. A call also fails with what the client
|
|
120
|
+
* `transformClient` returns fails with, as it is, and requires what that client requires.
|
|
119
121
|
*/
|
|
120
122
|
export declare function client<const H extends AnyHttp>(binding: H, options?: Options): Effect.Effect<Client<H>, never, HttpClient.HttpClient>;
|
|
123
|
+
export declare function client<const H extends AnyHttp, E, R>(binding: H, options: Options<E, R>): Effect.Effect<Client<H, E, R>, never, HttpClient.HttpClient>;
|
|
121
124
|
/**
|
|
122
125
|
* `client` built once over `fetch`, for code that holds a client outside an Effect, such as
|
|
123
|
-
* a browser app: its methods are the same Effects
|
|
124
|
-
* alone, as `Effect.runPromise(api.greet({ name }))`. The
|
|
125
|
-
* `fetch`.
|
|
126
|
+
* a browser app: its methods are the same Effects, which require only what `transformClient`
|
|
127
|
+
* requires, so a call without one runs alone, as `Effect.runPromise(api.greet({ name }))`. The
|
|
128
|
+
* options are `client`'s, and `fetch`.
|
|
126
129
|
*
|
|
127
130
|
* Each call sends with `options.fetch`, or with the global `fetch` as it is when the call
|
|
128
131
|
* runs.
|
|
129
132
|
*/
|
|
130
133
|
export declare function fetchClient<const H extends AnyHttp>(binding: H, options?: FetchClientOptions): Client<H>;
|
|
134
|
+
export declare function fetchClient<const H extends AnyHttp, E, R>(binding: H, options: FetchClientOptions<E, R>): Client<H, E, R>;
|
|
131
135
|
//#endregion
|
|
132
136
|
export { type AnyHttp as Any, type Client, type Options as ClientOptions, type MethodError, Options$1 as Options };
|
package/dist/ActionHttp.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { Anyone
|
|
1
|
+
import { Anyone } from "./contract/caller.mjs";
|
|
2
|
+
import { bindingErrors, bindingOf, projectedErrors } from "./contract/declared.mjs";
|
|
2
3
|
import { acquire, provideHandlers, servingOf } from "./contract/implementation.mjs";
|
|
3
4
|
import { providerOf } from "./authentication/provider.mjs";
|
|
4
5
|
import { inputParseOptions } from "./contract/call.mjs";
|
|
6
|
+
import { declared } from "./contract/status.mjs";
|
|
5
7
|
import { methods } from "./http/client.mjs";
|
|
6
8
|
import { SchemaErrors, schemaErrors } from "./http/schema-errors.mjs";
|
|
7
9
|
import { Context, Effect, Layer, Scope } from "effect";
|
package/dist/ActionMcp.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ActionOf, BuildError, BuildServices, Holding, Known, Member, Protected, SelectedOf, Selection, Served, ServedRequest } from "./contract/implementation.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Any } from "./Action.mjs";
|
|
3
3
|
import { Any as Any$1, Matching, ProviderOf, RemoteRequest, Required, ServerBuildServices } from "./authentication/provider.mjs";
|
|
4
4
|
import { Client, ClientOptions, McpCallError, Params, RequestOptions, client, request } from "./mcp/client.mjs";
|
|
5
5
|
import { Cause, Effect, Layer, Stdio } from "effect";
|
package/dist/ActionMcp.mjs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { Anyone, assertAuthentication
|
|
1
|
+
import { Anyone, assertAuthentication } from "./contract/caller.mjs";
|
|
2
|
+
import { assertOnce } from "./contract/names.mjs";
|
|
3
|
+
import { projectedErrors } from "./contract/declared.mjs";
|
|
4
|
+
import { hintsOf } from "./contract/hints.mjs";
|
|
2
5
|
import { acquire, provideHandlers, select, toList } from "./contract/implementation.mjs";
|
|
3
6
|
import { promote, providerOf } from "./authentication/provider.mjs";
|
|
4
7
|
import { inputParseOptions } from "./contract/call.mjs";
|
package/dist/ActionRpc.d.mts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Anyone
|
|
1
|
+
import { Anyone } from "./contract/caller.mjs";
|
|
2
2
|
import { BuiltIn, BuiltIns } from "./contract/errors.mjs";
|
|
3
3
|
import { BuildError, Holding, Known, Member, MiddlewareOf, Protected, Selected, Served, Serving } from "./contract/implementation.mjs";
|
|
4
4
|
import { Call } from "./contract/call.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { Any as Any$1, Errors } from "./Action.mjs";
|
|
6
6
|
import { Any as Any$2, DescriptorOf, Identity, Matching, PublicOnly, RemoteRequest, Required, ServedProvider, ServerBuildServices, VerifierError } from "./authentication/provider.mjs";
|
|
7
|
+
import { Certain, ErrorsOf } from "./contract/declared.mjs";
|
|
7
8
|
import { Context, Effect, Layer, Schema, Scope, Types } from "effect";
|
|
8
9
|
import { HttpRouter } from "effect/http";
|
|
9
10
|
import { Rpc, RpcClient, RpcClientError, RpcGroup, RpcMiddleware, RpcServer } from "effect/rpc";
|
|
@@ -144,4 +145,5 @@ export type ClientOptions = Omit<NonNullable<Parameters<typeof RpcClient.make>[1
|
|
|
144
145
|
* or with Effect's own `RpcClientError` when the server could not be reached.
|
|
145
146
|
*/
|
|
146
147
|
export declare function client<const B extends Any>(binding: B, options?: ClientOptions): Effect.Effect<Client<B>, never, RpcClient.Protocol | Scope.Scope>;
|
|
147
|
-
//#endregion
|
|
148
|
+
//#endregion
|
|
149
|
+
export {};
|
package/dist/ActionRpc.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Anyone
|
|
1
|
+
import { Anyone } from "./contract/caller.mjs";
|
|
2
|
+
import { bindingErrors, bindingOf } from "./contract/declared.mjs";
|
|
2
3
|
import { acquire, provideHandlers, servingOf } from "./contract/implementation.mjs";
|
|
3
4
|
import { providerOf } from "./authentication/provider.mjs";
|
|
4
5
|
import { checked, decodeInput } from "./contract/call.mjs";
|
package/dist/ActionToolkit.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BuiltIns } from "./contract/errors.mjs";
|
|
2
2
|
import { ActionOf, BuildError, BuildServices, Holding, Known, Member, Offered, OptionalUnless, RequestOf, SelectedOf, Served, Serving } from "./contract/implementation.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { Any } from "./Action.mjs";
|
|
4
4
|
import { Effect, Layer, Schema } from "effect";
|
|
5
5
|
import { Prompt, Tool, Toolkit } from "effect/ai";
|
|
6
6
|
//#region src/toolkit/ActionToolkit.d.ts
|
|
@@ -85,4 +85,5 @@ export interface Approval {
|
|
|
85
85
|
* `examples/kitchen-sink/src/assistant/handlers.ts`.
|
|
86
86
|
*/
|
|
87
87
|
export declare const openApprovals: ({ content: messages }: Prompt.Prompt) => ReadonlyArray<Approval>;
|
|
88
|
-
//#endregion
|
|
88
|
+
//#endregion
|
|
89
|
+
export {};
|
package/dist/ActionToolkit.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { assertOnce
|
|
1
|
+
import { assertOnce } from "./contract/names.mjs";
|
|
2
|
+
import { projectedErrors } from "./contract/declared.mjs";
|
|
3
|
+
import { hintsOf } from "./contract/hints.mjs";
|
|
2
4
|
import { Implementation, acquire, provideHandlers, select, toList } from "./contract/implementation.mjs";
|
|
3
5
|
import { Effect, Schema } from "effect";
|
|
4
6
|
import { Tool, Toolkit } from "effect/ai";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ErrorsOf } from "./contract/rules.mjs";
|
|
2
1
|
import { Refusal } from "./contract/errors.mjs";
|
|
3
2
|
import { Known, OptionalUnless } from "./contract/implementation.mjs";
|
|
4
3
|
import { Errors } from "./Action.mjs";
|
|
5
4
|
import { Any, Descriptor, Provider, Security } from "./authentication/provider.mjs";
|
|
5
|
+
import { ErrorsOf } from "./contract/declared.mjs";
|
|
6
6
|
import { Array, Context, Effect, Layer, Option, Redacted, Scope } from "effect";
|
|
7
7
|
import { HttpRouter, HttpServerResponse } from "effect/http";
|
|
8
8
|
import { HttpApiSecurity } from "effect/http-api";
|
package/dist/Authentication.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Unauthenticated, scopeToken } from "./contract/errors.mjs";
|
|
2
|
-
import { assertOwnTags, errorList } from "./contract/
|
|
2
|
+
import { assertOwnTags, errorList } from "./contract/declared.mjs";
|
|
3
3
|
import { providerOf } from "./authentication/provider.mjs";
|
|
4
4
|
import { answer, answerStepUp, bearer, challenge, declaredResponse, isRefusal, isStepUp, plain } from "./authentication/refusal.mjs";
|
|
5
5
|
import { Context, Effect, Layer, Match, Option, Predicate, Redacted } from "effect";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Anyone } from "../contract/
|
|
1
|
+
import { Anyone } from "../contract/caller.mjs";
|
|
2
2
|
import { Refusal } from "../contract/errors.mjs";
|
|
3
3
|
import { BuildServices, Protected, ServedRequest, Serving } from "../contract/implementation.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { Any as Any$1, Errors } from "../Action.mjs";
|
|
5
5
|
import { Context, Effect } from "effect";
|
|
6
6
|
import { HttpRouter, HttpServerResponse } from "effect/http";
|
|
7
7
|
import { HttpApiMiddleware, HttpApiSecurity } from "effect/http-api";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Forbidden, Refusal, Unauthenticated } from "../contract/errors.mjs";
|
|
2
|
-
import { declared, httpApiStatusOf } from "../contract/
|
|
2
|
+
import { declared, httpApiStatusOf } from "../contract/status.mjs";
|
|
3
3
|
import { Cause, Context, Effect, Exit, Option, Predicate, Ref, Schema } from "effect";
|
|
4
4
|
import { HttpServerResponse } from "effect/http";
|
|
5
5
|
//#region src/authentication/refusal.ts
|
package/dist/cli/commands.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../contract/errors.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { Effect, Runtime, Types } from "effect";
|
|
2
|
+
import { Any } from "../Action.mjs";
|
|
3
|
+
import { Effect, Option, Runtime, Types } from "effect";
|
|
4
4
|
import { CliError, Command } from "effect/cli";
|
|
5
5
|
//#region src/cli/commands.d.ts
|
|
6
6
|
type Field<A extends Any> = A["input"]["Encoded"] extends (infer E) ? true extends Types.IsUnion<E> ? never : E extends ReadonlyArray<unknown> ? never : E extends object ? string extends keyof E ? never : Extract<keyof E, string> : never : never;
|
|
@@ -44,4 +44,5 @@ export declare class UserError<out E = unknown> extends CliError.UserError {
|
|
|
44
44
|
get reason(): E;
|
|
45
45
|
get [Runtime.errorExitCode](): number;
|
|
46
46
|
}
|
|
47
|
-
//#endregion
|
|
47
|
+
//#endregion
|
|
48
|
+
export {};
|
package/dist/cli/commands.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { literalValues, members, unsuspended } from "../contract/ast.mjs";
|
|
1
2
|
import { InvalidInput } from "../contract/errors.mjs";
|
|
2
|
-
import { assertDistinct
|
|
3
|
+
import { assertDistinct } from "../contract/names.mjs";
|
|
3
4
|
import { decodeInput } from "../contract/call.mjs";
|
|
4
5
|
import { withStderrConsole } from "../stdio/console.mjs";
|
|
5
6
|
import { Console, Effect, Option, Predicate, Record, Runtime, Schema, SchemaAST, Stdio, Stream } from "effect";
|
|
@@ -205,8 +206,8 @@ const userErrorOf = (errors) => {
|
|
|
205
206
|
userMessage
|
|
206
207
|
}))));
|
|
207
208
|
};
|
|
208
|
-
const failingAsDerived = (
|
|
209
|
-
const failure = userErrorOf([...new Set(
|
|
209
|
+
const failingAsDerived = (errors) => {
|
|
210
|
+
const failure = userErrorOf([...new Set(errors)]);
|
|
210
211
|
return (self) => Effect.catchIf(self, (error) => !CliError.isCliError(error), failure);
|
|
211
212
|
};
|
|
212
213
|
const unreadableStdinField = (field, message) => new InvalidInput({
|
|
@@ -273,7 +274,7 @@ const command = (action, execute, options, errors) => {
|
|
|
273
274
|
const name = options?.name ?? kebab(action.name);
|
|
274
275
|
const render = options?.render;
|
|
275
276
|
const { flags, positional, decode, stdinHelp } = inputConfig(action, options?.positional ?? [], options?.aliases ?? {}, options?.stdin);
|
|
276
|
-
const
|
|
277
|
+
const failing = failingAsDerived(errors);
|
|
277
278
|
assertDistinct("flag", [
|
|
278
279
|
...Object.keys(flags).map((field) => [`--${kebab(field)}`, `field ${field}`]),
|
|
279
280
|
...render === void 0 ? [] : [["--json", "render's --json"]],
|
|
@@ -284,7 +285,7 @@ const command = (action, execute, options, errors) => {
|
|
|
284
285
|
...input,
|
|
285
286
|
...Object.fromEntries(positional.map(({ field }, index) => [field, values[index] ?? Option.none()]))
|
|
286
287
|
});
|
|
287
|
-
const run = (parsed, rendered) => decode(parsed).pipe(Effect.flatMap(execute),
|
|
288
|
+
const run = (parsed, rendered) => decode(parsed).pipe(Effect.flatMap(execute), failing, Effect.flatMap((value) => printedOutput(action, value, rendered)), withStderrConsole, Effect.flatMap(Option.match({
|
|
288
289
|
onNone: () => Effect.void,
|
|
289
290
|
onSome: Console.log
|
|
290
291
|
})));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SchemaAST } from "effect";
|
|
2
|
+
//#region src/contract/ast.ts
|
|
3
|
+
const unsuspended = (ast) => SchemaAST.isSuspend(ast) ? unsuspended(ast.thunk()) : ast;
|
|
4
|
+
const members = (ast) => {
|
|
5
|
+
const resolved = unsuspended(ast);
|
|
6
|
+
return SchemaAST.isUnion(resolved) ? resolved.types.flatMap(members) : [resolved];
|
|
7
|
+
};
|
|
8
|
+
const literalValues = (ast) => SchemaAST.isLiteral(ast) ? [ast.literal] : SchemaAST.isEnum(ast) ? ast.enums.map(([, value]) => value) : [void 0];
|
|
9
|
+
//#endregion
|
|
10
|
+
export { literalValues, members, unsuspended };
|
package/dist/contract/call.d.mts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "../Action.mjs";
|
|
2
|
+
//#region src/contract/caller.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The caller of a public action, `caller: Action.Anyone`: anyone, signed in or not, and no
|
|
5
|
+
* authorizer runs for it. Registered globally, so two copies of the package agree on it, as they
|
|
6
|
+
* agree on a name.
|
|
7
|
+
*/
|
|
8
|
+
export declare const Anyone: unique symbol;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/contract/caller.ts
|
|
2
|
+
/**
|
|
3
|
+
* The caller of a public action, `caller: Action.Anyone`: anyone, signed in or not, and no
|
|
4
|
+
* authorizer runs for it. Registered globally, so two copies of the package agree on it, as they
|
|
5
|
+
* agree on a name.
|
|
6
|
+
*/
|
|
7
|
+
const Anyone = Symbol.for("@gjermundgaraba/effect-actions/Anyone");
|
|
8
|
+
const assertAuthentication = (actions, authentication) => {
|
|
9
|
+
for (const action of actions) if (action.caller !== Anyone && (authentication === void 0 || action.caller.key !== authentication.identity.key)) throw new Error(`Protected action '${action.name}' requires its matching authentication descriptor`);
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { Anyone, assertAuthentication };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import "./caller.mjs";
|
|
2
|
+
import { Errors } from "../Action.mjs";
|
|
3
|
+
import { Types } from "effect";
|
|
4
|
+
//#region src/contract/declared.d.ts
|
|
4
5
|
type ListOf<G> = G extends Errors ? G : readonly [G];
|
|
5
6
|
/**
|
|
6
7
|
* The errors options `O` declare, as at run time: those `error` always gives, or, where it may
|
|
@@ -23,10 +24,5 @@ export interface Declaring {
|
|
|
23
24
|
readonly error: Errors;
|
|
24
25
|
} | undefined;
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* authorizer runs for it. Registered globally, so two copies of the package agree on it, as they
|
|
29
|
-
* agree on a name.
|
|
30
|
-
*/
|
|
31
|
-
export declare const Anyone: unique symbol;
|
|
32
|
-
//#endregion
|
|
27
|
+
//#endregion
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { literalValues, members } from "./ast.mjs";
|
|
2
|
+
import { Anyone, assertAuthentication } from "./caller.mjs";
|
|
3
|
+
import { builtIns } from "./errors.mjs";
|
|
4
|
+
import { assertOnce } from "./names.mjs";
|
|
5
|
+
import { Predicate, Schema, SchemaAST } from "effect";
|
|
6
|
+
//#region src/contract/declared.ts
|
|
7
|
+
const errorList = (error) => error === void 0 ? [] : Schema.isSchema(error) ? [error] : error;
|
|
8
|
+
const projectedErrors = (action, surface = []) => [.../* @__PURE__ */ new Set([
|
|
9
|
+
...builtIns,
|
|
10
|
+
...action.error,
|
|
11
|
+
...surface
|
|
12
|
+
])];
|
|
13
|
+
/**
|
|
14
|
+
* Every error a binding's call of `action` declares: the built-in ones, the action's, the
|
|
15
|
+
* binding's and, where `action` is protected, its authentication's.
|
|
16
|
+
*/
|
|
17
|
+
const bindingErrors = (action, binding) => projectedErrors(action, action.caller === Anyone || binding.authentication === void 0 ? binding.error : [...binding.error, ...binding.authentication.error]);
|
|
18
|
+
const encodedTags = (ast) => members(SchemaAST.toEncoded(ast)).flatMap((member) => {
|
|
19
|
+
const tag = SchemaAST.isObjects(member) ? member.propertySignatures.find((property) => property.name === "_tag")?.type : void 0;
|
|
20
|
+
return tag === void 0 ? [] : members(tag).flatMap(literalValues).filter(Predicate.isString);
|
|
21
|
+
});
|
|
22
|
+
const builtInTags = new Set(builtIns.flatMap((error) => encodedTags(error.ast)));
|
|
23
|
+
const assertOwnTags = (what, errors) => {
|
|
24
|
+
const tag = errors.flatMap((error) => encodedTags(error.ast)).find((tag) => builtInTags.has(tag));
|
|
25
|
+
if (tag !== void 0) throw new Error(`${what}: error _tag "${tag}" is built in, and declared on every surface`);
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The checks `ActionHttp.make` and `ActionRpc.make` share: each action once, no built-in error in
|
|
29
|
+
* `error`, and the descriptor every protected action names. Returns `error` as a list.
|
|
30
|
+
*/
|
|
31
|
+
const bindingOf = (what, actions, options) => {
|
|
32
|
+
assertOnce("action", actions);
|
|
33
|
+
const error = errorList(options.error);
|
|
34
|
+
assertOwnTags(what, error);
|
|
35
|
+
assertAuthentication(actions, options.authentication);
|
|
36
|
+
return {
|
|
37
|
+
error,
|
|
38
|
+
authentication: options.authentication
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { assertOwnTags, bindingErrors, bindingOf, errorList, projectedErrors };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/contract/hints.ts
|
|
2
|
+
/**
|
|
3
|
+
* An action's MCP tool hints, MCP's defaults where its `mcp` leaves one out: a write destructive,
|
|
4
|
+
* a read not, no tool idempotent and every tool open-world. A given value passes through, as MCP
|
|
5
|
+
* calls `destructiveHint` and `idempotentHint` meaningless on a read-only tool.
|
|
6
|
+
*/
|
|
7
|
+
const hintsOf = ({ readOnly, mcp }) => ({
|
|
8
|
+
readOnlyHint: readOnly,
|
|
9
|
+
destructiveHint: mcp.destructiveHint ?? !readOnly,
|
|
10
|
+
idempotentHint: mcp.idempotentHint ?? false,
|
|
11
|
+
openWorldHint: mcp.openWorldHint ?? true
|
|
12
|
+
});
|
|
13
|
+
//#endregion
|
|
14
|
+
export { hintsOf };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Anyone } from "./
|
|
1
|
+
import { Anyone } from "./caller.mjs";
|
|
2
2
|
import { Refusal } from "./errors.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { Any } from "../Action.mjs";
|
|
4
4
|
import { Context, Effect, Layer, Scope } from "effect";
|
|
5
5
|
//#region src/contract/implementation.d.ts
|
|
6
6
|
/** Decoded values at the dispatch boundary every surface shares. */
|
|
@@ -192,4 +192,5 @@ export type BuildServices<App, Listed extends Any = OwnActions<App>> = App exten
|
|
|
192
192
|
readonly "~buildServices": infer RX;
|
|
193
193
|
readonly "~authorizeBuildServices": infer RAX;
|
|
194
194
|
} ? RX | ([Protected<Serving<App, Listed>>] extends [never] ? never : RAX) : never;
|
|
195
|
-
//#endregion
|
|
195
|
+
//#endregion
|
|
196
|
+
export {};
|