@gjermundgaraba/effect-actions 0.1.0-rc.1 → 0.1.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 +50 -219
- package/dist/Action.d.mts +62 -2
- package/dist/Action.mjs +7 -4
- package/dist/ActionCatalog.d.mts +31 -0
- package/dist/ActionCatalog.mjs +36 -0
- package/dist/ActionCli.d.mts +27 -0
- package/dist/ActionCli.mjs +26 -0
- package/dist/ActionCliClient.d.mts +45 -0
- package/dist/ActionCliClient.mjs +52 -0
- package/dist/ActionGroup.d.mts +15 -14
- package/dist/ActionGroup.mjs +3 -2
- package/dist/ActionHttp.d.mts +21 -34
- package/dist/ActionHttp.mjs +44 -51
- package/dist/ActionMcp.d.mts +28 -7
- package/dist/ActionMcp.mjs +20 -128
- package/dist/ActionToolkit.d.mts +37 -0
- package/dist/ActionToolkit.mjs +10 -0
- package/dist/Authentication.d.mts +11 -12
- package/dist/Authentication.mjs +24 -57
- package/dist/Testing.d.mts +7 -4
- package/dist/Testing.mjs +4 -2
- package/dist/TestingClient.d.mts +6 -3
- package/dist/TestingClient.mjs +2 -2
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/internal/actions.d.mts +18 -0
- package/dist/internal/actions.mjs +16 -0
- package/dist/internal/cli.d.mts +29 -0
- package/dist/internal/cli.mjs +36 -0
- package/dist/internal/implementation.d.mts +39 -0
- package/dist/internal/implementation.mjs +37 -0
- package/dist/internal/tools.mjs +84 -0
- package/docs/Action.md +117 -0
- package/docs/ActionCatalog.md +56 -0
- package/docs/ActionCli.md +91 -0
- package/docs/ActionCliClient.md +77 -0
- package/docs/ActionGroup.md +141 -0
- package/docs/ActionHttp.md +106 -0
- package/docs/ActionMcp.md +131 -0
- package/docs/ActionToolkit.md +73 -0
- package/docs/Authentication.md +114 -0
- package/docs/CONTEXT.md +36 -0
- package/docs/README.md +85 -0
- package/docs/Testing.md +91 -0
- package/docs/guarantees.md +55 -0
- package/docs/setup.md +63 -0
- package/package.json +19 -14
- package/dist/Action-CXsfTEhx.d.mts +0 -54
- package/dist/implementation-4Q2BESw5.mjs +0 -61
- package/dist/implementation-DTqp_0DW.d.mts +0 -61
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect";
|
|
2
|
-
declare namespace Action_d_exports {
|
|
3
|
-
export { Action, Any, Codec, Handler, McpOptions, Options, SchemaErrorPolicy, SchemaFailure, make };
|
|
4
|
-
}
|
|
5
|
-
type Codec = Schema.Codec<unknown, unknown, never, never>;
|
|
6
|
-
/** Failed request decoding or successful-result encoding, independent of transport terminology. */
|
|
7
|
-
interface SchemaFailure {
|
|
8
|
-
readonly phase: "input" | "output";
|
|
9
|
-
/** May contain sensitive values. Do not reflect it in public error messages. */
|
|
10
|
-
readonly cause: Schema.SchemaError;
|
|
11
|
-
}
|
|
12
|
-
/** Pure application-owned mapping, set on a group and applied by both adapters. */
|
|
13
|
-
interface SchemaErrorPolicy<Errors extends ReadonlyArray<Codec>> {
|
|
14
|
-
readonly errors: Errors;
|
|
15
|
-
readonly map: (failure: SchemaFailure) => NoInfer<Errors[number]["Type"]>;
|
|
16
|
-
}
|
|
17
|
-
interface McpOptions {
|
|
18
|
-
readonly name?: string;
|
|
19
|
-
readonly readOnly?: boolean;
|
|
20
|
-
/** Defaults to `!readOnly`; the MCP spec only defines it for non-read-only tools. */
|
|
21
|
-
readonly destructive?: boolean;
|
|
22
|
-
}
|
|
23
|
-
interface Options<Input extends Codec, Output extends Codec, Errors extends ReadonlyArray<Codec>, Http extends boolean = boolean> {
|
|
24
|
-
readonly description: string;
|
|
25
|
-
/** Omit for an action without arguments. */
|
|
26
|
-
readonly input?: Input;
|
|
27
|
-
readonly success: Output;
|
|
28
|
-
/** One schema per declared failure; each keeps its own HTTP status annotation. Defaults to none. */
|
|
29
|
-
readonly errors?: Errors;
|
|
30
|
-
readonly http?: Http;
|
|
31
|
-
readonly mcp?: false | McpOptions;
|
|
32
|
-
}
|
|
33
|
-
/** A pure contract: schemas and transport metadata. Implementations are bound by `ActionGroup.implement`. */
|
|
34
|
-
interface Action<Name extends string, Input extends Codec, Output extends Codec, Errors extends ReadonlyArray<Codec>, Http extends boolean = boolean> {
|
|
35
|
-
readonly name: Name;
|
|
36
|
-
readonly description: string;
|
|
37
|
-
readonly input: Input;
|
|
38
|
-
readonly success: Output;
|
|
39
|
-
readonly errors: Errors;
|
|
40
|
-
readonly http: Http;
|
|
41
|
-
readonly mcp: false | {
|
|
42
|
-
readonly name: string;
|
|
43
|
-
readonly readOnly: boolean;
|
|
44
|
-
readonly destructive: boolean;
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
type Any = Action<string, Codec, Codec, ReadonlyArray<Codec>>;
|
|
48
|
-
/** Receives decoded input; may fail only with the declared errors. */
|
|
49
|
-
type Handler<A extends Any, R = never> = (input: A["input"]["Type"]) => Effect.Effect<A["success"]["Type"], A["errors"][number]["Type"], R>;
|
|
50
|
-
/** An empty object schema that also produces the object root MCP requires. */
|
|
51
|
-
declare const NoInput: Schema.$Record<Schema.String, Schema.Never>;
|
|
52
|
-
declare function make<const Name extends string, Input extends Codec = typeof NoInput, Output extends Codec = never, const Errors extends ReadonlyArray<Codec> = [], const Http extends boolean = true>(name: Name, options: Options<Input, Output, Errors, Http>): Action<Name, Input, Output, Errors, Http>;
|
|
53
|
-
//#endregion
|
|
54
|
-
export { Handler as a, SchemaErrorPolicy as c, __exportAll as d, Codec as i, SchemaFailure as l, Action_d_exports as n, McpOptions as o, Any as r, Options as s, Action as t, make as u };
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { Context, Effect, Layer } from "effect";
|
|
2
|
-
//#region src/internal/actions.ts
|
|
3
|
-
/** Each namespace is checked by whoever owns it: a group, the routes, or the MCP tools. */
|
|
4
|
-
const assertDistinct = (what, names) => {
|
|
5
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6
|
-
for (const name of names) {
|
|
7
|
-
if (seen.has(name)) throw new Error(`Duplicate ${what}: ${name}`);
|
|
8
|
-
seen.add(name);
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
const served = (groups, serves) => groups.flatMap((group) => {
|
|
12
|
-
const actions = group.actions.filter(serves);
|
|
13
|
-
return actions.length === 0 ? [] : [{
|
|
14
|
-
group,
|
|
15
|
-
actions
|
|
16
|
-
}];
|
|
17
|
-
});
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region src/internal/implementation.ts
|
|
20
|
-
let implementations = 0;
|
|
21
|
-
/**
|
|
22
|
-
* Opaque implementation value; only its type is public. `R` is required per
|
|
23
|
-
* request, `EX`/`RX` describe handler acquisition at Layer build. Layer
|
|
24
|
-
* memoization lets both adapters share one handler build per runtime.
|
|
25
|
-
*/
|
|
26
|
-
var Implementation = class Implementation {
|
|
27
|
-
group;
|
|
28
|
-
#handlers;
|
|
29
|
-
#layer;
|
|
30
|
-
constructor(group, handlers, layer) {
|
|
31
|
-
this.group = group;
|
|
32
|
-
this.#handlers = handlers;
|
|
33
|
-
this.#layer = layer;
|
|
34
|
-
}
|
|
35
|
-
static make(group, build) {
|
|
36
|
-
const handlers = Context.Service(`effect-actions/Handlers#${++implementations}`);
|
|
37
|
-
return new Implementation(group, handlers, Layer.effect(handlers, build));
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Acquire exactly the implementations an adapter serves. Each resolves its
|
|
41
|
-
* own handlers, so records are never merged across implementations.
|
|
42
|
-
*/
|
|
43
|
-
static register(serving, make) {
|
|
44
|
-
const [first, ...rest] = serving;
|
|
45
|
-
if (first === void 0) return make([]);
|
|
46
|
-
const bound = Effect.all(serving.map(({ app, actions }) => Effect.map(app.#handlers, (handlers) => ({
|
|
47
|
-
group: app.group,
|
|
48
|
-
actions,
|
|
49
|
-
handle: (action) => {
|
|
50
|
-
const handle = handlers[action.name];
|
|
51
|
-
if (handle === void 0) throw new Error(`Missing handler: ${action.name}`);
|
|
52
|
-
const dispatch = handle;
|
|
53
|
-
const name = `${app.group.name}.${action.name}`;
|
|
54
|
-
return (input) => Effect.withSpan(Effect.suspend(() => dispatch(input)), name, { captureStackTrace: false });
|
|
55
|
-
}
|
|
56
|
-
}))));
|
|
57
|
-
return Layer.unwrap(Effect.map(bound, make)).pipe(Layer.provide(Layer.mergeAll(first.app.#layer, ...rest.map(({ app }) => app.#layer))));
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
//#endregion
|
|
61
|
-
export { assertDistinct as n, served as r, Implementation as t };
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { c as SchemaErrorPolicy, i as Codec, n as Action_d_exports, r as Any } from "./Action-CXsfTEhx.mjs";
|
|
2
|
-
import { Effect, Layer, Scope } from "effect";
|
|
3
|
-
//#region src/internal/actions.d.ts
|
|
4
|
-
/** The contract half of a group: what adapters and clients need, without `implement`. */
|
|
5
|
-
interface Actions<Name extends string = string, A extends ReadonlyArray<Any> = ReadonlyArray<Any>, PolicyErrors extends ReadonlyArray<Codec> = ReadonlyArray<Codec>> {
|
|
6
|
-
readonly name: Name;
|
|
7
|
-
readonly actions: A;
|
|
8
|
-
/** How both transports answer failed decoding or encoding; their native behavior without one. */
|
|
9
|
-
readonly schemaError: SchemaErrorPolicy<PolicyErrors> | undefined;
|
|
10
|
-
}
|
|
11
|
-
/** The errors a group's policy may answer with, by lookup rather than a conditional type. */
|
|
12
|
-
type PolicyError<G extends Actions> = NonNullable<G["schemaError"]>["errors"][number];
|
|
13
|
-
/**
|
|
14
|
-
* What one adapter serves of a group. Each adapter projects its groups once and
|
|
15
|
-
* reads nothing else, so an action it does not serve cannot influence its
|
|
16
|
-
* names, routes, clients, pairing or acquisition.
|
|
17
|
-
*/
|
|
18
|
-
interface Served {
|
|
19
|
-
readonly group: Actions;
|
|
20
|
-
readonly actions: ReadonlyArray<Any>;
|
|
21
|
-
}
|
|
22
|
-
//#endregion
|
|
23
|
-
//#region src/internal/implementation.d.ts
|
|
24
|
-
/** Decoded action values after schema parsing, erased across actions at the adapter boundary. */
|
|
25
|
-
type ErasedValue = Any["input"]["Type"];
|
|
26
|
-
type Erased<R> = {
|
|
27
|
-
handle(input: ErasedValue): Effect.Effect<ErasedValue, ErasedValue, R>;
|
|
28
|
-
}["handle"];
|
|
29
|
-
type Handlers<R> = Readonly<Record<string, Erased<R>>>;
|
|
30
|
-
type Dispatch = (input: ErasedValue) => Effect.Effect<ErasedValue, ErasedValue>;
|
|
31
|
-
/** One acquired implementation and the actions its adapter serves. */
|
|
32
|
-
interface Bound extends Served {
|
|
33
|
-
readonly handle: (action: Any) => Dispatch;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Opaque implementation value; only its type is public. `R` is required per
|
|
37
|
-
* request, `EX`/`RX` describe handler acquisition at Layer build. Layer
|
|
38
|
-
* memoization lets both adapters share one handler build per runtime.
|
|
39
|
-
*/
|
|
40
|
-
declare class Implementation<G extends Actions, R, EX, RX> {
|
|
41
|
-
#private;
|
|
42
|
-
/** Adapters pair an implementation with its contract by this identity. */
|
|
43
|
-
readonly group: G;
|
|
44
|
-
private constructor();
|
|
45
|
-
static make<G extends Actions, R, EX, RX>(group: G, build: Effect.Effect<Handlers<R>, EX, RX>): Implementation<G, R, EX, Exclude<RX, Scope.Scope>>;
|
|
46
|
-
/**
|
|
47
|
-
* Acquire exactly the implementations an adapter serves. Each resolves its
|
|
48
|
-
* own handlers, so records are never merged across implementations.
|
|
49
|
-
*/
|
|
50
|
-
static register<R, EX, RX, Out, E, In>(serving: ReadonlyArray<{
|
|
51
|
-
readonly app: Implementation<Actions, R, EX, RX>;
|
|
52
|
-
readonly actions: ReadonlyArray<Any>;
|
|
53
|
-
}>, make: (apps: ReadonlyArray<Bound>) => Layer.Layer<Out, E, In>): Layer.Layer<Out, E | EX, In | RX>;
|
|
54
|
-
}
|
|
55
|
-
type AnyImplementation<G extends Actions = Actions> = Implementation<G, any, any, any>;
|
|
56
|
-
/** Per-request requirements of one implementation, or of a union of them. */
|
|
57
|
-
type RequestContext<App> = App extends Implementation<any, infer R, any, any> ? R : never;
|
|
58
|
-
type BuildError<App> = App extends Implementation<any, any, infer EX, any> ? EX : never;
|
|
59
|
-
type BuildContext<App> = App extends Implementation<any, any, any, infer RX> ? RX : never;
|
|
60
|
-
//#endregion
|
|
61
|
-
export { RequestContext as a, Implementation as i, BuildContext as n, Actions as o, BuildError as r, PolicyError as s, AnyImplementation as t };
|