@gjermundgaraba/effect-actions 0.14.0 → 0.16.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/dist/Action.d.mts +1 -1
- package/dist/ActionCli.d.mts +4 -6
- package/dist/ActionCli.mjs +11 -9
- package/dist/ActionHttp.mjs +18 -30
- package/dist/ActionMcp.d.mts +23 -7
- package/dist/ActionMcp.mjs +78 -90
- package/dist/ActionRpc.mjs +17 -29
- package/dist/ActionToolkit.mjs +26 -11
- package/dist/Authentication.mjs +1 -2
- package/dist/Testing.d.mts +6 -73
- package/dist/Testing.mjs +3 -102
- package/dist/authentication/provider.mjs +1 -6
- package/dist/authentication/refusal.mjs +14 -4
- package/dist/cli/commands.mjs +8 -8
- package/dist/contract/call.d.mts +2 -1
- package/dist/contract/call.mjs +14 -1
- package/dist/contract/errors.d.mts +2 -3
- package/dist/contract/errors.mjs +6 -12
- package/dist/contract/implementation.mjs +33 -5
- package/dist/contract/rules.d.mts +7 -0
- package/dist/contract/rules.mjs +50 -3
- package/dist/http/client.mjs +4 -7
- package/dist/mcp/client.d.mts +87 -0
- package/dist/mcp/client.mjs +122 -0
- package/dist/mcp/protocol.mjs +25 -37
- package/docs/Action.md +6 -5
- package/docs/ActionCli.md +4 -3
- package/docs/ActionMcp-failures.md +7 -2
- package/docs/ActionMcp.md +43 -46
- package/docs/ActionToolkit-failures.md +2 -1
- package/docs/ActionToolkit.md +2 -2
- package/docs/Authentication-failures.md +2 -2
- package/docs/Authentication.md +10 -5
- package/docs/CONTEXT.md +1 -1
- package/docs/Testing-failures.md +3 -3
- package/docs/Testing.md +16 -24
- package/docs/guarantees.md +15 -14
- package/examples/kitchen-sink/README.md +26 -26
- package/examples/kitchen-sink/test/attachments/attachments.test.ts +3 -2
- package/examples/kitchen-sink/test/identity/identity.test.ts +13 -6
- package/examples/kitchen-sink/test/routes.test.ts +4 -3
- package/examples/live-rpc/README.md +7 -2
- package/examples/mcp-tools/test/routes.test.ts +7 -6
- package/examples/notes-service/README.md +13 -3
- package/examples/notes-service/src/notes/Notes.ts +4 -2
- package/examples/notes-service/src/routes.ts +24 -14
- package/examples/notes-service/src/worker.ts +20 -0
- package/examples/notes-service/test/commands.test.ts +2 -1
- package/examples/notes-service/test/routes.test.ts +6 -3
- package/examples/notes-service/test/worker.test.ts +34 -0
- package/examples/quickstart/test/greeting/greeting.test.ts +2 -1
- package/package.json +1 -1
- package/dist/http/declared.mjs +0 -20
- package/dist/mcp/protocol.d.mts +0 -18
- package/dist/toolkit/tools.mjs +0 -29
package/dist/Action.d.mts
CHANGED
|
@@ -26,7 +26,7 @@ export interface Mcp {
|
|
|
26
26
|
* `annotations.destructiveHint`, meaningful for a write only. Left out, a write is listed as
|
|
27
27
|
* destructive, MCP's default: state `false` for one that only adds, MCP's "only additive
|
|
28
28
|
* updates". One that replaces, removes or interrupts, such as an edit or a restart, stays
|
|
29
|
-
* destructive.
|
|
29
|
+
* destructive, an update of a stored flag such as "read" included.
|
|
30
30
|
*/
|
|
31
31
|
readonly destructiveHint?: boolean | undefined;
|
|
32
32
|
/** `annotations.idempotentHint`, meaningful for a write only. */
|
package/dist/ActionCli.d.mts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
+
import { Declaring } from "./contract/rules.mjs";
|
|
1
2
|
import { BuiltIn } from "./contract/errors.mjs";
|
|
2
3
|
import { ActionOf, BuildError, BuildServices, Holding, Known, Member, RequestOf, Selected, SelectedOf, Selection, Served } from "./contract/implementation.mjs";
|
|
3
|
-
import { Action_d_exports, Any
|
|
4
|
+
import { Action_d_exports, Any } from "./Action.mjs";
|
|
4
5
|
import { VerifierError } from "./authentication/provider.mjs";
|
|
5
6
|
import { Options, UserError } from "./cli/commands.mjs";
|
|
6
7
|
import { AnyHttp, Options as Options$2 } from "./http/client.mjs";
|
|
8
|
+
import "./ActionHttp.mjs";
|
|
7
9
|
import { Effect, Schema } from "effect";
|
|
8
10
|
import { HttpClient, HttpClientError } from "effect/http";
|
|
9
11
|
import { Command } from "effect/cli";
|
|
10
12
|
//#region src/cli/ActionCli.d.ts
|
|
11
|
-
interface AnyBinding {
|
|
12
|
-
readonly authentication?: {
|
|
13
|
-
readonly error: Errors;
|
|
14
|
-
} | undefined;
|
|
13
|
+
interface AnyBinding extends Declaring {
|
|
15
14
|
readonly actions: ReadonlyArray<Any>;
|
|
16
|
-
readonly error: Errors;
|
|
17
15
|
}
|
|
18
16
|
/**
|
|
19
17
|
* Make a command of your own fail as a derived command does. Give it what the command calls, the
|
package/dist/ActionCli.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { assertDistinct, assertKnown } from "./contract/rules.mjs";
|
|
1
|
+
import { assertDistinct, assertKnown, bindingErrors, projectedErrors } from "./contract/rules.mjs";
|
|
2
2
|
import { Implementation, acquire, assertHeld, select, toList } from "./contract/implementation.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { assertInBinding, methods } from "./http/client.mjs";
|
|
3
|
+
import { client } from "./ActionHttp.mjs";
|
|
5
4
|
import { command as command$1, failingAsDerived } from "./cli/commands.mjs";
|
|
6
5
|
import { Cause, Effect, Logger, Runtime } from "effect";
|
|
7
6
|
import { Command } from "effect/cli";
|
|
@@ -17,8 +16,7 @@ import { Command } from "effect/cli";
|
|
|
17
16
|
* `Effect.tapError(() => Console.error(…))`: a `UserError` wrapped around the result would
|
|
18
17
|
* replace its JSON.
|
|
19
18
|
*/
|
|
20
|
-
const toUserError = (calls) => "actions" in calls ? failingAsDerived(calls.actions, (action) =>
|
|
21
|
-
const endpointErrorsOf = (binding, action) => withVerifierErrors(action, binding.error, binding.authentication?.error);
|
|
19
|
+
const toUserError = (calls) => "actions" in calls ? failingAsDerived(calls.actions, (action) => bindingErrors(action, calls)) : failingAsDerived(calls, (action) => projectedErrors(action));
|
|
22
20
|
const runWithBuildOfItsOwn = (app, action, input) => {
|
|
23
21
|
const thisActionOnly = Implementation.share([action], app);
|
|
24
22
|
return Effect.flatMap(acquire([thisActionOnly]), (bound) => {
|
|
@@ -34,11 +32,15 @@ const theImplementationOf = (apps, action) => {
|
|
|
34
32
|
};
|
|
35
33
|
const inProcess = (apps, action, options) => {
|
|
36
34
|
const app = theImplementationOf(apps, action);
|
|
37
|
-
return command$1(action, (input) => runWithBuildOfItsOwn(app, action, input), options);
|
|
35
|
+
return command$1(action, (input) => runWithBuildOfItsOwn(app, action, input), options, projectedErrors(action));
|
|
38
36
|
};
|
|
39
|
-
const overHttp = (binding, action, options, client) => {
|
|
40
|
-
|
|
41
|
-
return command$1(action, (input) => Effect.flatMap(
|
|
37
|
+
const overHttp = (binding, action, options, client$1) => {
|
|
38
|
+
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, client$1), (methods) => {
|
|
40
|
+
const method = methods[action.name];
|
|
41
|
+
if (method === void 0) throw new Error(`No client method for ${action.name}`);
|
|
42
|
+
return method(input);
|
|
43
|
+
}), options, bindingErrors(action, binding));
|
|
42
44
|
};
|
|
43
45
|
const aggregateCommand = (name, actions, commands, own, project) => {
|
|
44
46
|
const derived = actions.map((action) => ({
|
package/dist/ActionHttp.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Anyone,
|
|
2
|
-
import { acquire, provideHandlers,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Anyone, bindingErrors, bindingOf, declared, projectedErrors } from "./contract/rules.mjs";
|
|
2
|
+
import { acquire, provideHandlers, servingOf } from "./contract/implementation.mjs";
|
|
3
|
+
import { providerOf } from "./authentication/provider.mjs";
|
|
4
|
+
import { inputParseOptions } from "./contract/call.mjs";
|
|
5
5
|
import { methods } from "./http/client.mjs";
|
|
6
6
|
import { SchemaErrors, schemaErrors } from "./http/schema-errors.mjs";
|
|
7
7
|
import { Context, Effect, Layer, Scope } from "effect";
|
|
@@ -19,28 +19,24 @@ const apiOf = (group, endpoints) => {
|
|
|
19
19
|
const endpointOf = (action, path, errors) => HttpApiEndpoint.post(action.name, path, {
|
|
20
20
|
payload: action.input.pipe(HttpApiSchema.asJson()),
|
|
21
21
|
success: action.success,
|
|
22
|
-
error:
|
|
22
|
+
error: errors.flatMap(declared)
|
|
23
23
|
});
|
|
24
24
|
const withinLayerMiddleware = (endpoint, middleware = []) => middleware.reduce((inner, key) => inner.middleware(key), endpoint);
|
|
25
25
|
function make(actions, options = {}) {
|
|
26
|
-
|
|
27
|
-
const errors = errorList(options.error);
|
|
28
|
-
assertOwnTags("ActionHttp binding", errors);
|
|
29
|
-
assertAuthentication(actions, options.authentication);
|
|
26
|
+
const bound = bindingOf("ActionHttp binding", actions, options);
|
|
30
27
|
const mount = mountSegments(options.prefix);
|
|
31
|
-
const security =
|
|
28
|
+
const security = bound.authentication?.["~middleware"];
|
|
32
29
|
const endpoints = actions.map((action) => {
|
|
33
30
|
const isPublic = security === void 0 || action.caller === Anyone;
|
|
34
|
-
const endpoint = endpointOf(action, absolutePath([...mount, action.name]),
|
|
31
|
+
const endpoint = endpointOf(action, absolutePath([...mount, action.name]), bindingErrors(action, bound)).annotate(OpenApi.Description, action.description);
|
|
35
32
|
return isPublic ? endpoint : endpoint.middleware(security);
|
|
36
33
|
});
|
|
37
34
|
const api = apiOf(groupName(mount), endpoints);
|
|
38
35
|
return {
|
|
39
36
|
actions,
|
|
40
|
-
|
|
37
|
+
...bound,
|
|
41
38
|
prefix: absolutePath(mount),
|
|
42
|
-
api
|
|
43
|
-
authentication: options.authentication
|
|
39
|
+
api
|
|
44
40
|
};
|
|
45
41
|
}
|
|
46
42
|
const buildInEmptyContext = (group) => Layer.fromBuild((memoMap, scope) => Effect.setContext(Layer.buildWithMemoMap(group, memoMap, scope), Context.empty()));
|
|
@@ -52,40 +48,32 @@ var StepUp = class extends HttpApiMiddleware.Service()("effect-actions/ActionHtt
|
|
|
52
48
|
var JsonContentType = class extends HttpApiMiddleware.Service()("effect-actions/ActionHttp/JsonContentType") {};
|
|
53
49
|
const jsonContentType = () => Layer.succeed(JsonContentType, (route) => Effect.flatMap(HttpServerRequest.HttpServerRequest, (request) => request.headers["content-type"] === void 0 ? Effect.succeed(HttpServerResponse.text("Unsupported content-type: none", { status: 415 })) : route));
|
|
54
50
|
function layer(binding, served, options = {}) {
|
|
55
|
-
const apps =
|
|
56
|
-
const actions = apps.flatMap((app) => app.actions);
|
|
57
|
-
assertAuthentication(actions, binding.authentication);
|
|
58
|
-
assertDistinct("middleware", options.middleware ?? [], (key) => key.key);
|
|
51
|
+
const { apps, actions, authentication } = servingOf("HTTP binding", binding, served, options);
|
|
59
52
|
const mount = mountSegments(binding.prefix);
|
|
60
53
|
const name = groupName(mount);
|
|
61
54
|
const api = apiOf(name, actions.map((action) => {
|
|
62
|
-
const endpoint = withinLayerMiddleware(endpointOf(action, absolutePath([...mount, action.name]), binding.error).middleware(JsonContentType).middleware(SchemaErrors), options.middleware);
|
|
63
|
-
return action.caller === Anyone ||
|
|
64
|
-
})).annotate(HttpApi.PayloadParseOptions,
|
|
65
|
-
errors: "all",
|
|
66
|
-
onExcessProperty: "error"
|
|
67
|
-
});
|
|
55
|
+
const endpoint = withinLayerMiddleware(endpointOf(action, absolutePath([...mount, action.name]), projectedErrors(action, binding.error)).middleware(JsonContentType).middleware(SchemaErrors), options.middleware);
|
|
56
|
+
return action.caller === Anyone || authentication === void 0 ? endpoint : endpoint.middleware(StepUp).middleware(authentication["~middleware"]);
|
|
57
|
+
})).annotate(HttpApi.PayloadParseOptions, inputParseOptions);
|
|
68
58
|
const handlers = Layer.unwrap(Effect.gen(function* () {
|
|
69
59
|
const bound = yield* acquire(apps);
|
|
70
|
-
const
|
|
71
|
-
const authentication = auth === void 0 ? Layer.empty : yield* Effect.map(providerOf(auth), (provider) => Layer.mergeAll(Layer.succeed(auth["~middleware"], provider.middleware), Layer.succeed(StepUp, provider.stepUp)));
|
|
60
|
+
const security = authentication === void 0 ? Layer.empty : yield* Effect.map(providerOf(authentication), (provider) => Layer.mergeAll(Layer.succeed(authentication["~middleware"], provider.middleware), Layer.succeed(StepUp, provider.stepUp)));
|
|
72
61
|
const hostProvidedMiddleware = yield* Effect.forEach(options.middleware ?? [], (key) => Effect.map(Effect.service(key), (service) => Layer.succeed(key, service)));
|
|
73
62
|
const byName = Object.fromEntries(bound.map(([action, run]) => [action.name, (request) => run(request.payload)]));
|
|
74
63
|
return HttpApiBuilder.group(api, name, (builder) => builder.handleAll(byName)).pipe(Layer.provide([
|
|
75
64
|
schemaErrors(),
|
|
76
65
|
jsonContentType(),
|
|
77
|
-
|
|
66
|
+
security,
|
|
78
67
|
...hostProvidedMiddleware
|
|
79
68
|
]), buildInEmptyContext);
|
|
80
69
|
})).pipe(provideHandlers(apps));
|
|
81
70
|
return HttpApiBuilder.layer(api).pipe(Layer.provide(handlers), Layer.provide(startupBeneathRequest()));
|
|
82
71
|
}
|
|
83
|
-
const erasedClient = (binding, options) => Effect.map(methods(binding, options), (methodOf) => Object.fromEntries(binding.actions.map((action) => [action.name, methodOf(action)])));
|
|
84
72
|
function client(binding, options) {
|
|
85
|
-
return
|
|
73
|
+
return methods(binding, options);
|
|
86
74
|
}
|
|
87
75
|
function fetchClient(binding, { fetch, ...options } = {}) {
|
|
88
|
-
return
|
|
76
|
+
return methods(binding, options).pipe(Effect.provide(FetchHttpClient.layer), Effect.provideService(FetchHttpClient.Fetch, fetch ?? ((input, init) => globalThis.fetch(input, init))), Effect.runSync);
|
|
89
77
|
}
|
|
90
78
|
//#endregion
|
|
91
79
|
export { client, fetchClient, layer, make };
|
package/dist/ActionMcp.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ActionOf, BuildError, BuildServices, Holding, Known, Member, Protected, SelectedOf, Selection, Served, ServedRequest } from "./contract/implementation.mjs";
|
|
2
2
|
import { Action_d_exports, Any } from "./Action.mjs";
|
|
3
3
|
import { Any as Any$1, Matching, ProviderOf, RemoteRequest, Required, ServerBuildServices } from "./authentication/provider.mjs";
|
|
4
|
+
import { Client, ClientOptions, McpCallError, Params, RequestOptions, client, request } from "./mcp/client.mjs";
|
|
4
5
|
import { Cause, Effect, Layer, Stdio } from "effect";
|
|
5
6
|
import { McpSchema, McpServer } from "effect/ai";
|
|
6
7
|
import { HttpRouter } from "effect/http";
|
|
@@ -24,16 +25,29 @@ export interface Options<E = never, R = never, A extends Any = Any> extends Omit
|
|
|
24
25
|
readonly features?: Layer.Layer<never, E, R> | undefined;
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
|
-
* One Streamable HTTP MCP endpoint
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* defaulting to `/mcp`. A client of a 2025 revision opens a session with `initialize`, which
|
|
31
|
-
* lasts until that client ends it with a DELETE, answered 204, or the process stops.
|
|
28
|
+
* One Streamable HTTP MCP endpoint: `Options`, `authentication`, `requestScoped`, and every native
|
|
29
|
+
* `McpServer.layerHttp` option, `allowedOrigins` among them, except `protocols` and
|
|
30
|
+
* `allowSessionTermination`, which are fixed.
|
|
32
31
|
*/
|
|
33
32
|
export interface LayerHttpOptions<E = never, R = never, A extends Any = Any> extends Options<E, R, A>, Omit<Parameters<typeof McpServer.layerHttp>[0], "protocols" | "path" | "allowSessionTermination"> {
|
|
34
33
|
/** The endpoint's route; defaults to `/mcp`. */
|
|
35
34
|
readonly path?: HttpRouter.PathInput;
|
|
36
35
|
readonly authentication?: Any$1;
|
|
36
|
+
/**
|
|
37
|
+
* Whether MCP 2026-07-28 clients may subscribe, holding a stream open for list changes and
|
|
38
|
+
* resource updates. Defaults to whether `features` are given: an endpoint of actions alone
|
|
39
|
+
* registers its tools once, before any client connects, and serves no resource. Pass `true`
|
|
40
|
+
* where a handler changes the server through `McpServer.McpServer`.
|
|
41
|
+
*/
|
|
42
|
+
readonly allowSubscriptions?: boolean | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* `true` runs a server per request, as Effect's `McpServer.layerHttpRequestScoped` does, for a
|
|
45
|
+
* host such as Cloudflare Workers where nothing may outlive a request. It speaks MCP 2026-07-28
|
|
46
|
+
* alone, so a client that opens with `initialize` is refused, and it keeps no session. It has
|
|
47
|
+
* no subscriptions, so `allowSubscriptions` is ignored, and native `features` send no
|
|
48
|
+
* list-change notification and cannot use `McpServer.elicit`.
|
|
49
|
+
*/
|
|
50
|
+
readonly requestScoped?: boolean | undefined;
|
|
37
51
|
}
|
|
38
52
|
type ToolRequestContext<R> = Exclude<R, McpSchema.McpRequestContext | McpServer.McpServer>;
|
|
39
53
|
type HttpToolRequestContext<R> = Exclude<ToolRequestContext<R>, HttpRouter.Provided>;
|
|
@@ -47,7 +61,8 @@ type Inferring<D, A extends Any> = [D] extends [undefined] ? [Protected<A>] exte
|
|
|
47
61
|
* Serve MCP tools over one Streamable HTTP endpoint, speaking MCP 2026-07-28, 2025-11-25 or
|
|
48
62
|
* 2025-06-18, as the client negotiates. A 2026-07-28 request stands alone; a client of a 2025
|
|
49
63
|
* revision opens a session with `initialize`, which holds what it sent there and no identity,
|
|
50
|
-
* and lasts until that client ends it with a DELETE, answered 204, or the process stops.
|
|
64
|
+
* and lasts until that client ends it with a DELETE, answered 204, or the process stops. For a
|
|
65
|
+
* serverless host, see `requestScoped`.
|
|
51
66
|
*
|
|
52
67
|
* Protected tools need the `authentication` descriptor their contracts name, and the
|
|
53
68
|
* provider `Authentication.layer` builds from it. On an endpoint of protected tools only,
|
|
@@ -76,4 +91,5 @@ export declare function layerHttp<const Apps extends Served, const O extends Sel
|
|
|
76
91
|
* request identity or authority; each implementation's `authorize` runs for its protected actions.
|
|
77
92
|
*/
|
|
78
93
|
export declare function runStdio<const Apps extends Served, const O extends Selection<ActionOf<Member<Apps>>> = {}, E = never, R = never>(implementations: Apps, options: Options<E, R, ActionOf<Member<Apps>>> & O & NoInfer<Known<O, Options<E, R, Any>>>): Effect.Effect<void, BuildError<Holding<Member<Apps>, SelectedOf<O, Apps>>, SelectedOf<O, Apps>> | Cause.IllegalArgumentError | E, BuildServices<Holding<Member<Apps>, SelectedOf<O, Apps>>, SelectedOf<O, Apps>> | Stdio.Stdio | ToolRequestContext<ServedRequest<Member<Apps>, SelectedOf<O, Apps>>> | Features<R>>;
|
|
79
|
-
//#endregion
|
|
94
|
+
//#endregion
|
|
95
|
+
export { type Client, type ClientOptions, McpCallError, type Params, type RequestOptions, client, request };
|
package/dist/ActionMcp.mjs
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import { Anyone } from "./contract/rules.mjs";
|
|
2
|
-
import { provideHandlers, select, toList } from "./contract/implementation.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { Anyone, assertAuthentication, assertOnce, hintsOf, projectedErrors } from "./contract/rules.mjs";
|
|
2
|
+
import { acquire, provideHandlers, select, toList } from "./contract/implementation.mjs";
|
|
3
|
+
import { promote, providerOf } from "./authentication/provider.mjs";
|
|
4
|
+
import { inputParseOptions } from "./contract/call.mjs";
|
|
5
|
+
import { defaultPath, fieldKey, httpProtocol, isMisplaced, liftOf, liftedFrom, protocols } from "./mcp/protocol.mjs";
|
|
6
6
|
import { recordStepUp } from "./authentication/refusal.mjs";
|
|
7
7
|
import { withStderrConsole } from "./stdio/console.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { McpCallError, client, request } from "./mcp/client.mjs";
|
|
9
|
+
import { Cause, Context, Effect, ErrorReporter, Exit, Fiber, JsonPointer, Layer, Predicate, Schema } from "effect";
|
|
10
|
+
import { AiError, McpSchema, McpServer } from "effect/ai";
|
|
10
11
|
import { HttpRouter, HttpServerRequest } from "effect/http";
|
|
12
|
+
import { Base64 } from "effect/encoding";
|
|
11
13
|
//#region src/mcp/ActionMcp.ts
|
|
12
|
-
const strictToolProjection = {
|
|
13
|
-
label: "MCP tool",
|
|
14
|
-
tool: (tool) => tool.annotate(Tool.Strict, true)
|
|
15
|
-
};
|
|
16
14
|
const isToolArgumentsSchema = Schema.is(McpSchema.ToolJson);
|
|
17
|
-
const
|
|
15
|
+
const toolJsonSchema = (schema, strict) => {
|
|
18
16
|
const document = Schema.toJsonSchemaDocument(schema, { onExcessProperty: strict ? "error" : "ignore" });
|
|
19
17
|
const [scope, key] = Predicate.isString(document.schema.$ref) ? JsonPointer.parseUriFragment(document.schema.$ref) ?? [] : [];
|
|
20
18
|
const root = scope === "$defs" && key !== void 0 ? document.definitions[key] : document.schema;
|
|
@@ -24,7 +22,7 @@ const nativeToolJsonSchema = (schema, strict) => {
|
|
|
24
22
|
};
|
|
25
23
|
};
|
|
26
24
|
const assertToolShapes = (lifted) => {
|
|
27
|
-
const inputs = lifted.map(([action]) => action).filter((action) => !isToolArgumentsSchema(
|
|
25
|
+
const inputs = lifted.map(([action]) => action).filter((action) => !isToolArgumentsSchema(toolJsonSchema(Schema.toCodecJson(action.input), true))).map(({ name }) => name);
|
|
28
26
|
if (inputs.length > 0) throw new Error(`MCP tool input must be one object with keys, such as a struct: ${inputs.join(", ")}`);
|
|
29
27
|
const misplaced = lifted.filter(([action, lift]) => isMisplaced(action, lift)).map(([{ name }]) => name);
|
|
30
28
|
if (misplaced.length > 0) throw new Error(`MCP media must be the success or an array of it, or a top-level field of a struct success, one, optional or a required array: ${misplaced.join(", ")}`);
|
|
@@ -47,99 +45,84 @@ const contentBlockOf = ({ kind, field, value }) => ({
|
|
|
47
45
|
mimeType: value.mimeType,
|
|
48
46
|
...field === void 0 ? {} : { _meta: { [fieldKey]: field } }
|
|
49
47
|
});
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
const toolOf = (action, outputSchema) => Effect.map(Schema.decodeUnknownEffect(McpSchema.ToolJson)(toolJsonSchema(Schema.toCodecJson(action.input), true)), (inputSchema) => new McpSchema.Tool({
|
|
49
|
+
name: action.name,
|
|
50
|
+
description: action.description,
|
|
51
|
+
inputSchema,
|
|
52
|
+
outputSchema,
|
|
53
|
+
annotations: {
|
|
54
|
+
...action.mcp.title === void 0 ? {} : { title: action.mcp.title },
|
|
55
|
+
...hintsOf(action)
|
|
56
|
+
},
|
|
57
|
+
_meta: action.mcp._meta === void 0 ? void 0 : { ...action.mcp._meta }
|
|
58
|
+
}));
|
|
59
|
+
const registerTools = Effect.fnUntraced(function* (apps, authentication) {
|
|
53
60
|
const registry = yield* McpServer.McpServer;
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (Result.isSuccess(failure)) {
|
|
69
|
-
const { error } = failure.success;
|
|
70
|
-
const invalid = Context.get(Cause.reasonAnnotations(failure.success), Toolkit.FailureOrigin) === "parameters" ? parameterValidationErrorOf(error) : void 0;
|
|
71
|
-
if (invalid !== void 0) return Effect.fail(new McpSchema.InvalidParams({ message: invalid.message }));
|
|
72
|
-
}
|
|
73
|
-
return propagateInterruptOrReportInternal(cause);
|
|
74
|
-
};
|
|
75
|
-
const registrations = yield* Effect.forEach(Object.entries(built.tools), ([name, tool]) => Effect.gen(function* () {
|
|
76
|
-
const strict = Tool.getStrictMode(tool) === true;
|
|
77
|
-
const decodeOptions = {
|
|
78
|
-
onExcessProperty: strict ? "error" : "ignore",
|
|
79
|
-
errors: "all"
|
|
61
|
+
const bound = yield* acquire(apps);
|
|
62
|
+
const built = yield* Effect.context();
|
|
63
|
+
const internalError = (cause) => Effect.logError(cause).pipe(Effect.andThen(ErrorReporter.report(cause)), Effect.as(textErrorResult(nativeInternalErrorText)));
|
|
64
|
+
const internalErrorOnDefect = (cause) => Cause.hasDies(cause) ? internalError(cause) : Effect.failCause(cause);
|
|
65
|
+
for (const [action, run] of bound) {
|
|
66
|
+
const lift = liftOf(action.success);
|
|
67
|
+
const media = lift.fields.length === 0 ? void 0 : lift;
|
|
68
|
+
const structured = media === void 0 ? Schema.toCodecJson(action.success) : media.rest === void 0 ? void 0 : Schema.toCodecJson(media.rest);
|
|
69
|
+
const outputSchema = structured === void 0 ? void 0 : yield* Schema.decodeUnknownEffect(McpSchema.ToolOutputJson)(toolJsonSchema(structured, false)).pipe(Effect.orDie);
|
|
70
|
+
const tool = yield* toolOf(action, outputSchema).pipe(Effect.orDie);
|
|
71
|
+
const decode = Schema.decodeUnknownEffect(Schema.toCodecJson(action.input), inputParseOptions);
|
|
72
|
+
const encoder = (schema) => {
|
|
73
|
+
const encode = Schema.encodeUnknownEffect(Schema.toCodecJson(schema));
|
|
74
|
+
return (value) => Effect.orDie(encode(value));
|
|
80
75
|
};
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const outputSchema = structured === void 0 ? void 0 : yield* Schema.decodeUnknownEffect(McpSchema.ToolOutputJson)(nativeToolJsonSchema(structured, false)).pipe(Effect.orDie);
|
|
85
|
-
const inputSchema = yield* Schema.decodeUnknownEffect(McpSchema.ToolJson)(nativeToolJsonSchema(tool.parametersSchema, strict)).pipe(Effect.orDie);
|
|
76
|
+
const encodeSuccess = encoder(action.success);
|
|
77
|
+
const encodeFailure = encoder(Schema.Union(projectedErrors(action)));
|
|
78
|
+
const call = authentication === void 0 || action.caller === Anyone ? run : (input) => recordStepUp(promote(authentication, run(input)));
|
|
86
79
|
const liftedFieldNames = new Set(media?.fields.map(({ name }) => name));
|
|
87
|
-
const
|
|
80
|
+
const resultOf = (encoded, success) => {
|
|
88
81
|
if (media === void 0) return new McpSchema.CallToolResult({
|
|
89
82
|
isError: false,
|
|
90
|
-
structuredContent:
|
|
91
|
-
content: nativeJsonTextOf(
|
|
83
|
+
structuredContent: encoded,
|
|
84
|
+
content: nativeJsonTextOf(encoded)
|
|
92
85
|
});
|
|
93
|
-
const blocks = liftedFrom(media,
|
|
86
|
+
const blocks = liftedFrom(media, success).map(contentBlockOf);
|
|
94
87
|
if (structured === void 0) return new McpSchema.CallToolResult({
|
|
95
88
|
isError: false,
|
|
96
89
|
content: blocks
|
|
97
90
|
});
|
|
98
|
-
const encodedRestOfStruct = Predicate.isObject(
|
|
91
|
+
const encodedRestOfStruct = Predicate.isObject(encoded) ? Object.fromEntries(Object.entries(encoded).filter(([key]) => !liftedFieldNames.has(key))) : encoded;
|
|
99
92
|
return new McpSchema.CallToolResult({
|
|
100
93
|
isError: false,
|
|
101
94
|
structuredContent: encodedRestOfStruct,
|
|
102
95
|
content: [...nativeJsonTextOf(encodedRestOfStruct), ...blocks]
|
|
103
96
|
});
|
|
104
97
|
};
|
|
105
|
-
|
|
106
|
-
tool
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
content: nativeJsonTextOf(result.encodedResult)
|
|
124
|
-
})) : Effect.failCause(Cause.annotate(Cause.fail(result.result), Context.make(Toolkit.FailureOrigin, result.failureOrigin ?? "result")))), Effect.catchCause(invalidParamsOrInternal), Effect.provideContext(retainedServices))
|
|
125
|
-
};
|
|
126
|
-
}));
|
|
127
|
-
for (const registration of registrations) yield* registry.addTool(registration);
|
|
98
|
+
yield* registry.addTool({
|
|
99
|
+
tool,
|
|
100
|
+
annotations: Context.empty(),
|
|
101
|
+
handle: (payload) => Effect.annotateCurrentSpan({
|
|
102
|
+
tool: action.name,
|
|
103
|
+
parameters: payload ?? {}
|
|
104
|
+
}).pipe(Effect.andThen(() => decode(payload ?? {})), Effect.mapError(({ message }) => new McpSchema.InvalidParams({ message: new AiError.ToolParameterValidationError({
|
|
105
|
+
toolName: action.name,
|
|
106
|
+
description: message
|
|
107
|
+
}).message })), Effect.flatMap((input) => call(input).pipe(Effect.matchEffect({
|
|
108
|
+
onFailure: (error) => Effect.map(encodeFailure(error), (encoded) => new McpSchema.CallToolResult({
|
|
109
|
+
isError: true,
|
|
110
|
+
content: nativeJsonTextOf(encoded)
|
|
111
|
+
})),
|
|
112
|
+
onSuccess: (success) => Effect.map(encodeSuccess(success), (encoded) => resultOf(encoded, success))
|
|
113
|
+
}))), Effect.catchCause(internalErrorOnDefect), Effect.updateContext((request) => Context.merge(built, request)))
|
|
114
|
+
});
|
|
115
|
+
}
|
|
128
116
|
});
|
|
129
117
|
const server = (apps, transport, features = Layer.empty, authentication) => {
|
|
130
|
-
|
|
131
|
-
...strictToolProjection,
|
|
132
|
-
handler: (run, action) => (input) => action.caller === Anyone ? run(input) : recordStepUp(promote(authentication, run(input)))
|
|
133
|
-
});
|
|
118
|
+
assertOnce("MCP tool", apps.flatMap((app) => app.actions));
|
|
134
119
|
const lifted = apps.flatMap((app) => app.actions.map((action) => [action, liftOf(action.success)]));
|
|
135
120
|
assertToolShapes(lifted);
|
|
136
|
-
const
|
|
121
|
+
const names = new Set(lifted.map(([{ name }]) => name));
|
|
137
122
|
const register = Effect.gen(function* () {
|
|
138
|
-
const
|
|
139
|
-
const namesClaimedByFeatures = registry.tools.flatMap(({ tool }) => lifts.has(tool.name) ? [tool.name] : []);
|
|
123
|
+
const namesClaimedByFeatures = (yield* McpServer.McpServer).tools.flatMap(({ tool }) => names.has(tool.name) ? [tool.name] : []);
|
|
140
124
|
if (namesClaimedByFeatures.length > 0) return yield* Effect.die(/* @__PURE__ */ new Error(`Duplicate MCP tool: ${namesClaimedByFeatures.join(", ")}, claimed by an action and a native feature`));
|
|
141
|
-
|
|
142
|
-
yield* registerToolsLiftingMedia(binding.toolkit, lifts).pipe(Effect.setContext(Context.add(handlers, McpServer.McpServer, registry)));
|
|
125
|
+
yield* registerTools(apps, authentication);
|
|
143
126
|
});
|
|
144
127
|
return Layer.effectDiscard(register).pipe(Layer.provide(features), Layer.provide(transport), Layer.fresh, provideHandlers(apps));
|
|
145
128
|
};
|
|
@@ -149,7 +132,7 @@ const anonymousMethods = /* @__PURE__ */ new Set([
|
|
|
149
132
|
"notifications/cancelled"
|
|
150
133
|
]);
|
|
151
134
|
const requiresAuthentication = (actions) => {
|
|
152
|
-
const open = new Set(actions.filter(({ caller }) => caller === Anyone).
|
|
135
|
+
const open = new Set(actions.filter(({ caller }) => caller === Anyone).flatMap(({ name }) => [name, `=?base64?${Base64.encode(name)}?=`]));
|
|
153
136
|
return (headers) => {
|
|
154
137
|
if (open.size === 0) return true;
|
|
155
138
|
if (headers["mcp-protocol-version"] !== httpProtocol.protocolVersion) return true;
|
|
@@ -165,15 +148,20 @@ const namesItsMethod = (request) => Effect.match(request.json, {
|
|
|
165
148
|
onFailure: () => true,
|
|
166
149
|
onSuccess: (body) => !Predicate.hasProperty(body, "method") || body.method === request.headers["mcp-method"]
|
|
167
150
|
});
|
|
168
|
-
function layerHttp(apps, { actions, features, path, authentication, ...options }) {
|
|
151
|
+
function layerHttp(apps, { actions, features, path = defaultPath, authentication, requestScoped, allowSubscriptions = features !== void 0, ...options }) {
|
|
169
152
|
const selected = select(toList(apps), actions);
|
|
170
153
|
const served = selected.flatMap((app) => app.actions);
|
|
171
154
|
assertAuthentication(served, authentication);
|
|
172
|
-
const transport = server(selected, McpServer.
|
|
155
|
+
const transport = server(selected, requestScoped === true ? McpServer.layerHttpRequestScoped({
|
|
156
|
+
...options,
|
|
157
|
+
path,
|
|
158
|
+
protocols: [httpProtocol]
|
|
159
|
+
}) : McpServer.layerHttp({
|
|
173
160
|
...options,
|
|
174
|
-
path
|
|
161
|
+
path,
|
|
175
162
|
protocols,
|
|
176
|
-
allowSessionTermination: true
|
|
163
|
+
allowSessionTermination: true,
|
|
164
|
+
allowSubscriptions
|
|
177
165
|
}), features, authentication);
|
|
178
166
|
if (authentication === void 0) return transport;
|
|
179
167
|
const required = requiresAuthentication(served);
|
|
@@ -188,4 +176,4 @@ function runStdio(apps, { actions, features, ...options }) {
|
|
|
188
176
|
return Layer.launch(transport).pipe(withStderrConsole, Effect.forkChild, Effect.flatMap(Fiber.await), Effect.flatMap((exit) => Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause) ? Effect.failCause(exit.cause) : Effect.void));
|
|
189
177
|
}
|
|
190
178
|
//#endregion
|
|
191
|
-
export { layerHttp, runStdio };
|
|
179
|
+
export { McpCallError, client, layerHttp, request, runStdio };
|
package/dist/ActionRpc.mjs
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { checked } from "./contract/call.mjs";
|
|
5
|
-
import { assertAuthentication, providerOf, withVerifierErrors } from "./authentication/provider.mjs";
|
|
1
|
+
import { Anyone, bindingErrors, bindingOf } from "./contract/rules.mjs";
|
|
2
|
+
import { acquire, provideHandlers, servingOf } from "./contract/implementation.mjs";
|
|
3
|
+
import { providerOf } from "./authentication/provider.mjs";
|
|
4
|
+
import { checked, decodeInput } from "./contract/call.mjs";
|
|
6
5
|
import { Cause, Effect, ErrorReporter, Layer, Predicate, Result, Schema, SchemaTransformation } from "effect";
|
|
7
6
|
import { HttpClientRequest, HttpServerRequest } from "effect/http";
|
|
8
7
|
import { HttpApiBuilder } from "effect/http-api";
|
|
9
8
|
import { Rpc, RpcClient, RpcGroup, RpcSerialization, RpcServer } from "effect/rpc";
|
|
10
9
|
//#region src/rpc/ActionRpc.ts
|
|
11
|
-
const declaredErrorsOf = (action, errors, authentication) => projectedErrors(action, withVerifierErrors(action, errors, authentication?.error));
|
|
12
10
|
function make(actions, options = {}) {
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
const bound = bindingOf("ActionRpc binding", actions, options);
|
|
12
|
+
const group = RpcGroup.make(...actions.map((action) => Rpc.make(action.name, {
|
|
13
|
+
payload: action.input,
|
|
14
|
+
success: action.success,
|
|
15
|
+
error: Schema.Union(bindingErrors(action, bound))
|
|
16
|
+
})));
|
|
17
17
|
return {
|
|
18
18
|
actions,
|
|
19
|
-
|
|
20
|
-
group
|
|
21
|
-
payload: action.input,
|
|
22
|
-
success: action.success,
|
|
23
|
-
error: Schema.Union(declaredErrorsOf(action, errors, options.authentication))
|
|
24
|
-
}))),
|
|
25
|
-
authentication: options.authentication
|
|
19
|
+
...bound,
|
|
20
|
+
group
|
|
26
21
|
};
|
|
27
22
|
}
|
|
28
23
|
const credentialFromRpcHeaders = (security, headers) => HttpApiBuilder.securityDecode(security).pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromClientRequest(HttpClientRequest.get("/", { headers }))), Effect.provideService(HttpServerRequest.ParsedSearchParams, {}));
|
|
@@ -60,14 +55,11 @@ const callBoundaryOf = (error) => {
|
|
|
60
55
|
});
|
|
61
56
|
};
|
|
62
57
|
const handlerOf = (action, run, steps, error) => {
|
|
63
|
-
const
|
|
64
|
-
errors: "all",
|
|
65
|
-
onExcessProperty: "error"
|
|
66
|
-
});
|
|
58
|
+
const decode = decodeInput(action);
|
|
67
59
|
const encode = Schema.encodeUnknownEffect(Schema.toCodecJson(action.success));
|
|
68
60
|
const boundary = callBoundaryOf(error);
|
|
69
61
|
return (payload, options) => {
|
|
70
|
-
const call = Effect.suspend(() =>
|
|
62
|
+
const call = Effect.suspend(() => decode(payload)).pipe(Effect.flatMap(run), Effect.flatMap(encode));
|
|
71
63
|
const wrapped = steps.reduce((inner, step) => Effect.suspend(() => step(inner, {
|
|
72
64
|
...options,
|
|
73
65
|
payload
|
|
@@ -76,12 +68,8 @@ const handlerOf = (action, run, steps, error) => {
|
|
|
76
68
|
};
|
|
77
69
|
};
|
|
78
70
|
function layer(binding, served, options = {}) {
|
|
79
|
-
const apps =
|
|
80
|
-
const actions = apps.flatMap((app) => app.actions);
|
|
81
|
-
assertAuthentication(actions, binding.authentication);
|
|
71
|
+
const { apps, actions, authentication } = servingOf("RPC binding", binding, served, options);
|
|
82
72
|
const middleware = options.middleware ?? [];
|
|
83
|
-
assertDistinct("middleware", middleware, (key) => key.key);
|
|
84
|
-
const auth = actions.some((action) => action.caller !== Anyone) ? binding.authentication : void 0;
|
|
85
73
|
const jsonGroup = RpcGroup.make(...actions.map((action) => Rpc.make(action.name, {
|
|
86
74
|
payload: Schema.Json,
|
|
87
75
|
success: Schema.Json,
|
|
@@ -91,9 +79,9 @@ function layer(binding, served, options = {}) {
|
|
|
91
79
|
const { codecFor } = yield* RpcServer.Protocol;
|
|
92
80
|
if (codecFor !== RpcSerialization.json.codecFor) return yield* Effect.die(/* @__PURE__ */ new Error("ActionRpc serves a protocol speaking JSON: RpcSerialization.layerJson, layerNdjson, layerJsonRpc or layerNdJsonRpc, not another codec, such as schema-binary's"));
|
|
93
81
|
const listedMiddleware = yield* Effect.forEach(middleware, (key) => Effect.service(key));
|
|
94
|
-
const authenticate =
|
|
82
|
+
const authenticate = authentication === void 0 ? void 0 : yield* authenticationStepOf(authentication);
|
|
95
83
|
const bound = yield* acquire(apps);
|
|
96
|
-
const byName = Object.fromEntries(bound.map(([action, run]) => [action.name, handlerOf(action, run, action.caller === Anyone || authenticate === void 0 ? listedMiddleware : [...listedMiddleware, authenticate], Schema.Union(
|
|
84
|
+
const byName = Object.fromEntries(bound.map(([action, run]) => [action.name, handlerOf(action, run, action.caller === Anyone || authenticate === void 0 ? listedMiddleware : [...listedMiddleware, authenticate], Schema.Union(bindingErrors(action, binding)))]));
|
|
97
85
|
return jsonGroup.toLayer(byName);
|
|
98
86
|
})).pipe(provideHandlers(apps));
|
|
99
87
|
return RpcServer.layer(jsonGroup, { disableFatalDefects: true }).pipe(Layer.provide(handlers));
|
package/dist/ActionToolkit.mjs
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { assertOnce, hintsOf, projectedErrors } from "./contract/rules.mjs";
|
|
2
|
+
import { Implementation, acquire, provideHandlers, select, toList } from "./contract/implementation.mjs";
|
|
3
|
+
import { Effect, Schema } from "effect";
|
|
4
|
+
import { Tool, Toolkit } from "effect/ai";
|
|
3
5
|
//#region src/toolkit/ActionToolkit.ts
|
|
6
|
+
const annotateIfGiven = (tool, key, value) => value === void 0 ? tool : tool.annotate(key, value);
|
|
7
|
+
const annotateFromContract = (tool, action) => {
|
|
8
|
+
const { readOnlyHint, destructiveHint, idempotentHint, openWorldHint } = hintsOf(action);
|
|
9
|
+
const { title, _meta } = action.mcp;
|
|
10
|
+
const hinted = tool.annotate(Tool.Readonly, readOnlyHint).annotate(Tool.Destructive, destructiveHint).annotate(Tool.Idempotent, idempotentHint).annotate(Tool.OpenWorld, openWorldHint);
|
|
11
|
+
return annotateIfGiven(annotateIfGiven(hinted, Tool.Title, title), Tool.Meta, _meta === void 0 ? void 0 : { ..._meta });
|
|
12
|
+
};
|
|
13
|
+
const jsonToolOf = (action) => Tool.make(action.name, {
|
|
14
|
+
description: action.description,
|
|
15
|
+
parameters: Schema.toCodecJson(action.input),
|
|
16
|
+
success: Schema.toCodecJson(action.success),
|
|
17
|
+
failure: Schema.toCodecJson(Schema.Union(projectedErrors(action))),
|
|
18
|
+
failureMode: "return"
|
|
19
|
+
});
|
|
4
20
|
function make(apps, options) {
|
|
5
21
|
const served = select(toList(apps), options?.actions);
|
|
6
22
|
const needsApproval = options?.needsApproval;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
});
|
|
23
|
+
assertOnce("tool", served.flatMap((app) => app.actions));
|
|
24
|
+
const toolOf = (action, app) => Object.assign(needsApproval === void 0 ? jsonToolOf(action) : jsonToolOf(action).setNeedsApproval((input, context) => needsApproval({
|
|
25
|
+
name: action.name,
|
|
26
|
+
action,
|
|
27
|
+
input
|
|
28
|
+
}, context)), { id: `${Implementation.runKey(app)}/${action.name}` });
|
|
29
|
+
const toolkit = Toolkit.make(...served.flatMap((app) => app.actions.map((action) => annotateFromContract(toolOf(action, app), action))));
|
|
15
30
|
return {
|
|
16
31
|
toolkit,
|
|
17
|
-
layer:
|
|
32
|
+
layer: toolkit.toLayer(Effect.map(acquire(served), (bound) => Object.fromEntries(bound.map(([action, run]) => [action.name, run])))).pipe(provideHandlers(served))
|
|
18
33
|
};
|
|
19
34
|
}
|
|
20
35
|
/**
|
package/dist/Authentication.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Unauthenticated, scopeToken } from "./contract/errors.mjs";
|
|
2
2
|
import { assertOwnTags, errorList } from "./contract/rules.mjs";
|
|
3
3
|
import { providerOf } from "./authentication/provider.mjs";
|
|
4
|
-
import { answer, answerStepUp, bearer, challenge, isRefusal, isStepUp, plain } from "./authentication/refusal.mjs";
|
|
5
|
-
import { declaredResponse } from "./http/declared.mjs";
|
|
4
|
+
import { answer, answerStepUp, bearer, challenge, declaredResponse, isRefusal, isStepUp, plain } from "./authentication/refusal.mjs";
|
|
6
5
|
import { Context, Effect, Layer, Match, Option, Predicate, Redacted } from "effect";
|
|
7
6
|
import { HttpEffect, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
8
7
|
import { HttpApiBuilder, HttpApiMiddleware, HttpApiSecurity } from "effect/http-api";
|