@gjermundgaraba/effect-actions 0.11.0 → 0.12.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.
Files changed (215) hide show
  1. package/README.md +101 -40
  2. package/dist/Action.d.mts +29 -117
  3. package/dist/Action.mjs +14 -53
  4. package/dist/ActionCli.d.mts +60 -28
  5. package/dist/ActionCli.mjs +54 -48
  6. package/dist/ActionHttp.d.mts +18 -67
  7. package/dist/ActionHttp.mjs +20 -70
  8. package/dist/ActionMcp.d.mts +23 -29
  9. package/dist/ActionMcp.mjs +56 -114
  10. package/dist/ActionRpc.d.mts +147 -0
  11. package/dist/ActionRpc.mjs +113 -0
  12. package/dist/ActionToolkit.d.mts +5 -8
  13. package/dist/ActionToolkit.mjs +3 -3
  14. package/dist/Authentication.d.mts +15 -15
  15. package/dist/Authentication.mjs +42 -96
  16. package/dist/Testing.d.mts +28 -23
  17. package/dist/Testing.mjs +27 -44
  18. package/dist/{internal/authentication.d.mts → authentication/provider.d.mts} +41 -9
  19. package/dist/authentication/provider.mjs +12 -0
  20. package/dist/authentication/refusal.mjs +36 -0
  21. package/dist/{internal/cli.d.mts → cli/commands.d.mts} +16 -12
  22. package/dist/cli/commands.mjs +302 -0
  23. package/dist/{internal → contract}/call.d.mts +2 -2
  24. package/dist/contract/call.mjs +10 -0
  25. package/dist/{internal → contract}/errors.d.mts +13 -10
  26. package/dist/{internal → contract}/errors.mjs +9 -14
  27. package/dist/{internal → contract}/implementation.d.mts +37 -21
  28. package/dist/{internal → contract}/implementation.mjs +18 -49
  29. package/dist/contract/media.d.mts +13 -0
  30. package/dist/contract/media.mjs +18 -0
  31. package/dist/contract/rules.d.mts +25 -0
  32. package/dist/{internal/actions.mjs → contract/rules.mjs} +6 -42
  33. package/dist/{internal → http}/client.d.mts +7 -9
  34. package/dist/http/client.mjs +17 -0
  35. package/dist/http/declared.mjs +20 -0
  36. package/dist/http/schema-errors.mjs +9 -0
  37. package/dist/mcp/protocol.d.mts +17 -0
  38. package/dist/{internal/mcp.mjs → mcp/protocol.mjs} +29 -62
  39. package/dist/stdio/console.mjs +64 -0
  40. package/dist/{internal → testing}/memory.d.mts +1 -1
  41. package/dist/{internal → testing}/memory.mjs +5 -17
  42. package/dist/toolkit/tools.mjs +29 -0
  43. package/docs/Action-failures.md +47 -0
  44. package/docs/Action-in-process.md +93 -0
  45. package/docs/Action.md +206 -426
  46. package/docs/ActionCli-failures.md +102 -0
  47. package/docs/ActionCli.md +206 -293
  48. package/docs/ActionHttp-failures.md +83 -0
  49. package/docs/ActionHttp.md +202 -282
  50. package/docs/ActionMcp-failures.md +31 -0
  51. package/docs/ActionMcp.md +222 -271
  52. package/docs/ActionRpc-failures.md +21 -0
  53. package/docs/ActionRpc.md +178 -0
  54. package/docs/ActionToolkit-failures.md +15 -0
  55. package/docs/ActionToolkit.md +100 -119
  56. package/docs/Authentication-advanced.md +139 -0
  57. package/docs/Authentication-failures.md +99 -0
  58. package/docs/Authentication.md +142 -392
  59. package/docs/CONTEXT.md +39 -24
  60. package/docs/README.md +71 -35
  61. package/docs/Testing-failures.md +20 -0
  62. package/docs/Testing.md +186 -151
  63. package/docs/guarantees.md +35 -96
  64. package/docs/setup-failures.md +34 -0
  65. package/docs/setup.md +87 -91
  66. package/examples/README.md +68 -0
  67. package/examples/assistant/README.md +92 -0
  68. package/examples/assistant/src/agent.ts +92 -0
  69. package/examples/assistant/src/cli.ts +34 -0
  70. package/examples/assistant/src/commands.ts +25 -0
  71. package/examples/assistant/src/identity/Identity.ts +33 -0
  72. package/examples/assistant/src/identity/authorize.ts +24 -0
  73. package/examples/assistant/src/identity/handlers.ts +10 -0
  74. package/examples/assistant/src/identity/members.ts +9 -0
  75. package/examples/assistant/src/identity/permissions.ts +23 -0
  76. package/examples/assistant/src/scripted.ts +23 -0
  77. package/examples/assistant/src/tasks/Tasks.ts +63 -0
  78. package/examples/assistant/src/tasks/handlers.ts +25 -0
  79. package/examples/assistant/src/tasks/store.ts +96 -0
  80. package/examples/assistant/src/toolkit.ts +30 -0
  81. package/examples/assistant/test/commands.test.ts +57 -0
  82. package/examples/assistant/test/identity/identity.test.ts +43 -0
  83. package/examples/assistant/test/tasks/store.test.ts +48 -0
  84. package/examples/assistant/test/tasks/tasks.test.ts +75 -0
  85. package/examples/assistant/test/toolkit.test.ts +121 -0
  86. package/examples/kitchen-sink/README.md +317 -0
  87. package/examples/kitchen-sink/src/Actions.ts +19 -0
  88. package/examples/kitchen-sink/src/Api.ts +24 -0
  89. package/examples/kitchen-sink/src/Rpc.ts +12 -0
  90. package/examples/kitchen-sink/src/admin/Admin.ts +59 -0
  91. package/examples/kitchen-sink/src/admin/authenticate.ts +18 -0
  92. package/examples/kitchen-sink/src/admin/authorize.ts +27 -0
  93. package/examples/kitchen-sink/src/admin/grants.ts +22 -0
  94. package/examples/kitchen-sink/src/admin/handlers.ts +21 -0
  95. package/examples/kitchen-sink/src/admin/keys.ts +8 -0
  96. package/examples/kitchen-sink/src/agent.ts +47 -0
  97. package/examples/kitchen-sink/src/assistant/Assistant.ts +82 -0
  98. package/examples/kitchen-sink/src/assistant/conversations.ts +71 -0
  99. package/examples/kitchen-sink/src/assistant/demo-model.ts +33 -0
  100. package/examples/kitchen-sink/src/assistant/handlers.ts +146 -0
  101. package/examples/kitchen-sink/src/attachments/Attachments.ts +48 -0
  102. package/examples/kitchen-sink/src/attachments/download.ts +49 -0
  103. package/examples/kitchen-sink/src/attachments/handlers.ts +38 -0
  104. package/examples/kitchen-sink/src/attachments/store.ts +58 -0
  105. package/examples/kitchen-sink/src/browser.ts +33 -0
  106. package/examples/kitchen-sink/src/cli.ts +85 -0
  107. package/examples/kitchen-sink/src/config.ts +18 -0
  108. package/examples/kitchen-sink/src/identity/Identity.ts +61 -0
  109. package/examples/kitchen-sink/src/identity/authenticate.ts +87 -0
  110. package/examples/kitchen-sink/src/identity/authorize.ts +16 -0
  111. package/examples/kitchen-sink/src/identity/directory.ts +52 -0
  112. package/examples/kitchen-sink/src/identity/handlers.ts +9 -0
  113. package/examples/kitchen-sink/src/identity/members.ts +13 -0
  114. package/examples/kitchen-sink/src/identity/quota.ts +62 -0
  115. package/examples/kitchen-sink/src/issues/Issues.ts +109 -0
  116. package/examples/kitchen-sink/src/issues/assistant.ts +23 -0
  117. package/examples/kitchen-sink/src/issues/guide.ts +37 -0
  118. package/examples/kitchen-sink/src/issues/handlers.ts +37 -0
  119. package/examples/kitchen-sink/src/issues/store.ts +96 -0
  120. package/examples/kitchen-sink/src/issues/write-limit.ts +41 -0
  121. package/examples/kitchen-sink/src/memory.ts +30 -0
  122. package/examples/kitchen-sink/src/ops.ts +42 -0
  123. package/examples/kitchen-sink/src/request-policy.ts +63 -0
  124. package/examples/kitchen-sink/src/routes.ts +120 -0
  125. package/examples/kitchen-sink/src/sdk.ts +46 -0
  126. package/examples/kitchen-sink/src/seed.ts +65 -0
  127. package/examples/kitchen-sink/src/server.ts +62 -0
  128. package/examples/kitchen-sink/src/stdio.ts +34 -0
  129. package/examples/kitchen-sink/src/workspaces/Workspaces.ts +28 -0
  130. package/examples/kitchen-sink/src/workspaces/handlers.ts +23 -0
  131. package/examples/kitchen-sink/src/workspaces/registry.ts +46 -0
  132. package/examples/kitchen-sink/src/workspaces/tenant.ts +17 -0
  133. package/examples/kitchen-sink/test/admin/admin.test.ts +67 -0
  134. package/examples/kitchen-sink/test/assistant/assistant.test.ts +435 -0
  135. package/examples/kitchen-sink/test/attachments/attachments.test.ts +161 -0
  136. package/examples/kitchen-sink/test/identity/identity.test.ts +137 -0
  137. package/examples/kitchen-sink/test/identity/session.test.ts +110 -0
  138. package/examples/kitchen-sink/test/issues/assistant.test.ts +75 -0
  139. package/examples/kitchen-sink/test/issues/issues.test.ts +135 -0
  140. package/examples/kitchen-sink/test/request-policy.test.ts +125 -0
  141. package/examples/kitchen-sink/test/routes.test.ts +123 -0
  142. package/examples/kitchen-sink/test/support/scripted.ts +40 -0
  143. package/examples/live-rpc/README.md +107 -0
  144. package/examples/live-rpc/src/Rpc.ts +8 -0
  145. package/examples/live-rpc/src/browser.ts +98 -0
  146. package/examples/live-rpc/src/chat/Chat.ts +75 -0
  147. package/examples/live-rpc/src/chat/authorize.ts +16 -0
  148. package/examples/live-rpc/src/chat/handlers.ts +50 -0
  149. package/examples/live-rpc/src/chat/room.ts +23 -0
  150. package/examples/live-rpc/src/chat/store.ts +54 -0
  151. package/examples/live-rpc/src/client.ts +37 -0
  152. package/examples/live-rpc/src/identity/Identity.ts +19 -0
  153. package/examples/live-rpc/src/identity/members.ts +8 -0
  154. package/examples/live-rpc/src/identity/verifier.ts +23 -0
  155. package/examples/live-rpc/src/routes.ts +22 -0
  156. package/examples/live-rpc/src/server.ts +43 -0
  157. package/examples/live-rpc/test/browser.test.ts +105 -0
  158. package/examples/live-rpc/test/chat/chat.test.ts +69 -0
  159. package/examples/live-rpc/test/routes.test.ts +99 -0
  160. package/examples/live-rpc/test/server.test.ts +75 -0
  161. package/examples/mcp-tools/README.md +136 -0
  162. package/examples/mcp-tools/src/instructions.ts +12 -0
  163. package/examples/mcp-tools/src/printers/Printers.ts +119 -0
  164. package/examples/mcp-tools/src/printers/fake.ts +115 -0
  165. package/examples/mcp-tools/src/printers/farm.ts +136 -0
  166. package/examples/mcp-tools/src/printers/handlers.ts +29 -0
  167. package/examples/mcp-tools/src/routes.ts +52 -0
  168. package/examples/mcp-tools/src/server.ts +30 -0
  169. package/examples/mcp-tools/src/stdio.ts +26 -0
  170. package/examples/mcp-tools/test/printers/printers.test.ts +189 -0
  171. package/examples/mcp-tools/test/routes.test.ts +202 -0
  172. package/examples/notes-service/README.md +108 -0
  173. package/examples/notes-service/src/Api.ts +13 -0
  174. package/examples/notes-service/src/browser.ts +41 -0
  175. package/examples/notes-service/src/cli.ts +22 -0
  176. package/examples/notes-service/src/commands.ts +89 -0
  177. package/examples/notes-service/src/identity/Identity.ts +31 -0
  178. package/examples/notes-service/src/identity/authorize.ts +18 -0
  179. package/examples/notes-service/src/identity/handlers.ts +10 -0
  180. package/examples/notes-service/src/identity/users.ts +9 -0
  181. package/examples/notes-service/src/identity/verifier.ts +36 -0
  182. package/examples/notes-service/src/notes/Notes.ts +91 -0
  183. package/examples/notes-service/src/notes/handlers.ts +33 -0
  184. package/examples/notes-service/src/notes/store.ts +73 -0
  185. package/examples/notes-service/src/routes.ts +45 -0
  186. package/examples/notes-service/src/server.ts +26 -0
  187. package/examples/notes-service/src/status/Status.ts +10 -0
  188. package/examples/notes-service/src/status/handlers.ts +14 -0
  189. package/examples/notes-service/src/stdio.ts +25 -0
  190. package/examples/notes-service/test/commands.test.ts +134 -0
  191. package/examples/notes-service/test/notes/notes.test.ts +103 -0
  192. package/examples/notes-service/test/routes.test.ts +84 -0
  193. package/examples/quickstart/README.md +31 -0
  194. package/examples/quickstart/src/Api.ts +5 -0
  195. package/examples/quickstart/src/client.ts +13 -0
  196. package/examples/quickstart/src/greeting/Greeting.ts +12 -0
  197. package/examples/quickstart/src/greeting/handlers.ts +6 -0
  198. package/examples/quickstart/src/routes.ts +11 -0
  199. package/examples/quickstart/src/server.ts +16 -0
  200. package/examples/quickstart/test/greeting/greeting.test.ts +18 -0
  201. package/package.json +23 -5
  202. package/dist/internal/actions.d.mts +0 -9
  203. package/dist/internal/authentication.mjs +0 -11
  204. package/dist/internal/call.mjs +0 -12
  205. package/dist/internal/cli.mjs +0 -328
  206. package/dist/internal/client.mjs +0 -25
  207. package/dist/internal/console.mjs +0 -77
  208. package/dist/internal/declared.d.mts +0 -13
  209. package/dist/internal/declared.mjs +0 -34
  210. package/dist/internal/mcp.d.mts +0 -14
  211. package/dist/internal/media.d.mts +0 -8
  212. package/dist/internal/media.mjs +0 -26
  213. package/dist/internal/refusal.mjs +0 -67
  214. package/dist/internal/schema-errors.mjs +0 -20
  215. package/dist/internal/tools.mjs +0 -44
@@ -1,328 +0,0 @@
1
- import { InvalidInput } from "./errors.mjs";
2
- import { assertDistinct, literalValues, members, projectedErrors, unsuspended } from "./actions.mjs";
3
- import { logToStderr } from "./console.mjs";
4
- import { Console, Effect, Option, Predicate, Record, Runtime, Schema, SchemaAST } from "effect";
5
- import { CliError, Command, Flag, Param } from "effect/cli";
6
- //#region src/internal/cli.ts
7
- /**
8
- * `getUser` as a command or flag name: `get-user`; `getHTTPUser`: `get-http-user`; `_id`:
9
- * `id`, since a flag already starts with its dashes. A name of dashes and underscores alone,
10
- * which would be left empty, is kept as it is.
11
- */
12
- const kebab = (name) => {
13
- const kebabbed = name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
14
- return kebabbed === "" ? name : kebabbed;
15
- };
16
- /**
17
- * A command with a renderer takes `--json` as a flag of its own, so nothing is
18
- * claimed tree-wide and a host's `--json`, global or not, is never contested.
19
- * Without a renderer the output is JSON already and there is no flag.
20
- */
21
- const jsonFlag = Flag.Boolean("json").pipe(Flag.withDefault(false), Flag.withDescription("Print machine-readable JSON"));
22
- /** The kinds of JSON value there are. */
23
- const jsonKinds = [
24
- "null",
25
- "boolean",
26
- "number",
27
- "string",
28
- "array",
29
- "object"
30
- ];
31
- /** The kind of a JSON value, or of a literal's, which JSON has no bigint for. */
32
- const kindOf = (value) => value === null ? "null" : Predicate.isBoolean(value) ? "boolean" : Predicate.isNumber(value) ? "number" : Predicate.isString(value) ? "string" : Array.isArray(value) ? "array" : "object";
33
- /**
34
- * The kinds of JSON value an encoded type accepts at its top, each member's of a union and a
35
- * suspended type's: its checks and what it nests aside, which the action's schema decodes.
36
- * A type of no fixed kind accepts all.
37
- */
38
- const kindsOf = (ast) => members(ast).flatMap((member) => {
39
- if (SchemaAST.isLiteral(member)) return [kindOf(member.literal)];
40
- if (SchemaAST.isEnum(member)) return member.enums.map(([, value]) => kindOf(value));
41
- if (SchemaAST.isNull(member)) return ["null"];
42
- if (SchemaAST.isBoolean(member)) return ["boolean"];
43
- if (SchemaAST.isNumber(member)) return ["number"];
44
- if (SchemaAST.isString(member) || SchemaAST.isTemplateLiteral(member)) return ["string"];
45
- if (SchemaAST.isArrays(member)) return ["array"];
46
- if (SchemaAST.isObjects(member)) return ["object"];
47
- return jsonKinds;
48
- });
49
- /**
50
- * A flag's text as the JSON it holds when the field's `encoded` type accepts that kind of
51
- * value, or else as itself, for the action's schema to decode: for a number `21` parses,
52
- * while for `"auto" | string` the text `true` stays text. Only the kind is checked, so JSON
53
- * breaking a rule of the schema, such as a maximum length, stays JSON, and the action's
54
- * schema reports the rule and the path to what breaks it.
55
- */
56
- const jsonOrText = (encoded) => {
57
- const accepted = new Set(kindsOf(encoded));
58
- return Schema.Union([Schema.fromJsonString(Schema.Json).check(Schema.makeFilter((json) => accepted.has(kindOf(json)))), Schema.String]);
59
- };
60
- /** The strings a union of string literals or a string enum accepts, if it is one. */
61
- const choices = (ast) => {
62
- const accepted = members(ast).flatMap(literalValues);
63
- return accepted.every(Predicate.isString) ? accepted : void 0;
64
- };
65
- /**
66
- * The native flag or argument parsing one field's encoded JSON value: a string or boolean
67
- * for those, a choice for string literals and string enums, and JSON or text for anything
68
- * else, numbers included. A template literal is a string; the action's schema checks its
69
- * pattern. A suspended type is read as the type it stands for. JSON or text, a flag's or an
70
- * argument's, is shown as `value`, not as the string it is parsed from.
71
- */
72
- const valueParam = (kind, name, field) => {
73
- const encoded = unsuspended(field);
74
- const literals = choices(encoded);
75
- if (literals !== void 0) return Param.Literals(kind, name, literals);
76
- if (SchemaAST.isString(encoded) || SchemaAST.isTemplateLiteral(encoded)) return Param.String(kind, name);
77
- if (SchemaAST.isBoolean(encoded)) return Param.Boolean(kind, name);
78
- return Param.String(kind, name).pipe(Param.withSchema(jsonOrText(encoded)), Param.withMetavar("value"));
79
- };
80
- /**
81
- * An optional field's value without the absence `Schema.optional` adds to it: `undefined`
82
- * declared, `null` encoded. Omitting the flag already leaves the field out, so
83
- * `optional(Schema.String)` takes a plain string.
84
- */
85
- const present = (ast) => {
86
- const members = SchemaAST.isUnion(ast) ? ast.types.filter((member) => !SchemaAST.isNull(member) && !SchemaAST.isUndefined(member)) : [];
87
- return members.length === 1 && members[0] !== void 0 ? members[0] : ast;
88
- };
89
- /**
90
- * Whether `Schema.optional` added the field's JSON `null`: encoded without the JSON codec,
91
- * its value admits `undefined` but not `null`. A `null` of the field's own schema, as
92
- * `NullOr` or `OptionFromNullOr` encode, stays.
93
- */
94
- const addsNull = (plain) => {
95
- const types = members(plain);
96
- return types.some(SchemaAST.isUndefined) && !types.some(SchemaAST.isNull);
97
- };
98
- /**
99
- * The element of an encoded array a flag repeats, and how many times it must: an array of
100
- * strings or numbers, choices included, whose fixed first elements, if any, are its rest's,
101
- * as `Schema.NonEmptyArray` writes one. `undefined` for any other array, which takes JSON.
102
- */
103
- const repeated = (ast) => {
104
- const encoded = unsuspended(ast);
105
- if (!SchemaAST.isArrays(encoded)) return void 0;
106
- const [element, ...after] = encoded.rest;
107
- if (element === void 0 || after.length > 0 || !encoded.elements.every((first) => first === element) || !kindsOf(element).every((kind) => kind === "string" || kind === "number")) return;
108
- return {
109
- element,
110
- min: encoded.elements.length
111
- };
112
- };
113
- /** The occurrence of a repeated flag that adds no element, so `--tag '[]'` alone is `[]`. */
114
- const empty = "[]";
115
- /**
116
- * A field's flag or argument, `None` when omitted, from its JSON encoding and its plain one.
117
- * A required field's is required, so the parser reports it missing; a required boolean flag
118
- * is a switch instead: omitted, it is `false`, as a switch reads. A boolean argument takes
119
- * `true` or `false`. A flag or argument of an array of strings or numbers is repeated, one
120
- * element per occurrence but `[]`, which adds none, and a choice among the element's: none
121
- * is `[]`, or leaves an optional field out, which `[]` gives instead.
122
- */
123
- const fieldParam = (kind, name, encoded, plain) => {
124
- const optional = SchemaAST.isOptional(encoded);
125
- const value = optional && plain !== void 0 && addsNull(plain) ? present(encoded) : encoded;
126
- const repeats = repeated(value);
127
- if (repeats !== void 0) {
128
- const literals = choices(unsuspended(repeats.element));
129
- const elements = literals === void 0 ? valueParam(kind, name, repeats.element) : Param.Literals(kind, name, [...literals, empty]);
130
- const listed = (values) => Option.some(values.filter((value) => value !== empty));
131
- return {
132
- param: optional ? Param.variadic(elements).pipe(Param.map((values) => values.length === 0 ? Option.none() : listed(values))) : Param.variadic(elements, { min: repeats.min }).pipe(Param.map(listed)),
133
- repeats: true
134
- };
135
- }
136
- if (optional) return {
137
- param: Param.optional(valueParam(kind, name, value)),
138
- repeats: false
139
- };
140
- return {
141
- param: kind === Param.flagKind && SchemaAST.isBoolean(unsuspended(encoded)) ? Flag.Boolean(name).pipe(Flag.withDefault(false), Flag.map(Option.some)) : valueParam(kind, name, encoded).pipe(Param.map(Option.some)),
142
- repeats: false
143
- };
144
- };
145
- /**
146
- * The fields of a struct, or of a class, which declares them as its one type parameter, by name.
147
- */
148
- const fieldsOf = (ast) => {
149
- const fields = SchemaAST.isDeclaration(ast) ? ast.typeParameters[0] : ast;
150
- return new Map(fields !== void 0 && SchemaAST.isObjects(fields) ? fields.propertySignatures.map((property) => [property.name, property.type]) : []);
151
- };
152
- /** A struct, or a class's, transformed as a whole, as `Schema.encodeKeys` transforms one. */
153
- const transformedWhole = (ast) => (SchemaAST.isDeclaration(ast) ? ast.typeParameters[0] : ast)?.encoding !== void 0;
154
- /** A field's description: its own, or the first a suspension it stands for has. */
155
- const descriptionOf = (ast) => SchemaAST.resolveDescription(ast) ?? (SchemaAST.isSuspend(ast) ? descriptionOf(ast.thunk()) : void 0);
156
- /**
157
- * One flag or argument per top-level field of a struct input, named after the field in
158
- * kebab case, parsed as its encoded value and described by its declared schema: an
159
- * argument for a field listed in `positional`, a flag otherwise. A field required once
160
- * encoded is required; the action's schema still decodes what they parse.
161
- */
162
- const fieldParams = (encoded, input, positional, aliases) => {
163
- const plain = fieldsOf(SchemaAST.toEncoded(input));
164
- const described = fieldsOf(transformedWhole(input) ? encoded : SchemaAST.toType(input));
165
- return encoded.propertySignatures.map((property) => {
166
- const field = String(property.name);
167
- const declaredField = described.get(property.name);
168
- const kind = positional.includes(field) ? Param.argumentKind : Param.flagKind;
169
- const { param, repeats } = fieldParam(kind, kebab(field), property.type, plain.get(property.name));
170
- const alias = kind === Param.flagKind ? aliases[field] : void 0;
171
- const aliased = alias === void 0 ? param : Param.withAlias(param, alias);
172
- const documented = declaredField ?? property.type;
173
- const description = descriptionOf(documented) ?? descriptionOf(present(documented));
174
- return {
175
- field,
176
- param: description === void 0 ? aliased : Param.withDescription(aliased, description),
177
- optional: SchemaAST.isOptional(property.type),
178
- repeats
179
- };
180
- });
181
- };
182
- /**
183
- * The positional fields in order, checked against the fields there are: each one a field,
184
- * listed once, and every required one before any optional one, as a parser reads them.
185
- */
186
- const positionalOrder = (params, positional) => {
187
- assertDistinct("positional argument", positional, (field) => field);
188
- const ordered = positional.map((field) => {
189
- const found = params.find((param) => param.field === field);
190
- if (found === void 0) throw new Error(`Not an input field: ${field}`);
191
- return found;
192
- });
193
- const firstOptional = ordered.findIndex((param) => param.optional);
194
- const misplaced = ordered.slice(firstOptional === -1 ? ordered.length : firstOptional).find((param) => !param.optional);
195
- if (misplaced !== void 0) throw new Error(`Required positional argument after an optional one: ${misplaced.field}`);
196
- const greedy = ordered.slice(0, -1).find((param) => param.repeats);
197
- if (greedy !== void 0) throw new Error(`Repeated positional argument before another one: ${greedy.field}`);
198
- return ordered;
199
- };
200
- /**
201
- * `--input`, the whole encoded input as JSON, or text, for an input that is not a struct of
202
- * fields. It is never required: left off, it is `{}`, which the action's schema decodes
203
- * when the command runs, never when it is built.
204
- */
205
- const inputFlag = (encoded) => Flag.String("input").pipe(Flag.withSchema(jsonOrText(encoded)), Flag.withDescription("Whole action input as JSON; omitted, {}"), Flag.optional);
206
- /**
207
- * What a success prints on stdout: its JSON, or `render`'s text. It is validated and encoded
208
- * first, so human output cannot conceal an invalid success, which is a defect, as on a server.
209
- * An action that returns nothing prints nothing, rather than its encoding, `null`.
210
- */
211
- const output = (action, value, render) => Effect.map(Effect.orDie(Schema.encodeEffect(Schema.toCodecJson(action.success))(value)), (encoded) => render === void 0 && SchemaAST.isVoid(action.success.ast) ? Option.none() : Option.some(render === void 0 ? JSON.stringify(encoded, null, 2) : render(value)));
212
- /**
213
- * What a command fails with when its action fails: Effect CLI's own error for a handler's
214
- * failure, which `Command.run` prints on stderr and marks reported, so `runMain` does not
215
- * print it again. Its `cause` is the action's failure. The process exits with the cause's
216
- * `Runtime.errorExitCode`, 1 by default.
217
- */
218
- var UserError = class extends CliError.UserError {
219
- /**
220
- * The action's failure, as Effect names an error's nested one, so the native
221
- * `Effect.catchReason("UserError", "UserNotFound", f)` and `catchReasons` match it by tag.
222
- */
223
- get reason() {
224
- return this.cause;
225
- }
226
- get [Runtime.errorExitCode]() {
227
- return Runtime.getErrorExitCode(this.cause);
228
- }
229
- };
230
- /** `error`'s own `_tag` or `message`, when it is a string. */
231
- const text = (error, key) => {
232
- if (!Predicate.hasProperty(error, key)) return void 0;
233
- const value = error[key];
234
- return Predicate.isString(value) ? value : void 0;
235
- };
236
- /**
237
- * A failure no projected schema encodes, without a stack: its tag or an error's name, and
238
- * its message, or the failure itself when it is a string, then each cause's, so a transport
239
- * error keeps the refused connection beneath it, up to one already described, as a cycle
240
- * repeats it. Its other fields are left out, a plain object's `name` too: no schema says
241
- * they are safe to show, and a builder's failure may hold a connection string.
242
- */
243
- const described = (error, seen = /* @__PURE__ */ new Set()) => {
244
- const name = text(error, "_tag") ?? (error instanceof Error ? error.name : "Error");
245
- const message = Predicate.isString(error) ? error : text(error, "message") ?? "";
246
- const named = message === "" ? name : `${name}: ${message}`;
247
- seen.add(error);
248
- return Predicate.hasProperty(error, "cause") && error.cause !== void 0 && !seen.has(error.cause) ? `${named}: ${described(error.cause, seen)}` : named;
249
- };
250
- /**
251
- * The `UserError` of each failure of `action`, its message the JSON HTTP sends for it: encoded
252
- * by the first schema that takes it among the built-in errors, the action's and the
253
- * surface's own `errors`, as an Effect, as HTTP encodes it. A failure none takes, such as a
254
- * builder's or the transport's, is described instead.
255
- */
256
- const failureOf = (action, errors) => {
257
- const encode = Schema.encodeUnknownEffect(Schema.fromJsonString(Schema.toCodecJson(Schema.Union(projectedErrors(action, errors)))));
258
- return (error) => encode(error).pipe(Effect.orElseSucceed(() => described(error)), Effect.flatMap((userMessage) => Effect.fail(new UserError({
259
- cause: error,
260
- userMessage
261
- }))));
262
- };
263
- /**
264
- * The action's input as native flags: one per field of a struct input, named after it,
265
- * or `--input` taking the whole input as JSON otherwise. The `positional` fields of a
266
- * struct are arguments instead, in that order.
267
- */
268
- const inputConfig = (action, positional, aliases) => {
269
- const codec = Schema.toCodecJson(action.input);
270
- const encoded = unsuspended(SchemaAST.toEncoded(codec.ast));
271
- const decode = Schema.decodeUnknownEffect(codec, { onExcessProperty: "error" });
272
- if (SchemaAST.isObjects(encoded) && encoded.indexSignatures.every((signature) => SchemaAST.isNever(signature.type))) {
273
- const params = fieldParams(encoded, unsuspended(action.input.ast), positional, aliases);
274
- const flagged = new Set(params.map(({ field }) => field).filter((field) => !positional.includes(field)));
275
- const stray = Object.keys(aliases).find((field) => !flagged.has(field));
276
- if (stray !== void 0) throw new Error(`Not a flag's input field: ${stray}`);
277
- return {
278
- flags: Object.fromEntries(params.flatMap(({ field, param }) => positional.includes(field) ? [] : [[field, param]])),
279
- positional: positionalOrder(params, positional),
280
- decode: (parsed) => decode(Record.getSomes(parsed))
281
- };
282
- }
283
- if (positional.length > 0) throw new Error(`Positional arguments need named input fields: ${positional.join(", ")}`);
284
- if (Object.keys(aliases).length > 0) throw new Error(`Aliases need named input fields: ${Object.keys(aliases).join(", ")}`);
285
- return {
286
- flags: { input: inputFlag(encoded) },
287
- positional: [],
288
- decode: (parsed) => decode(Option.getOrElse(parsed["input"] ?? Option.none(), () => ({})))
289
- };
290
- };
291
- /**
292
- * One native command around an action-bound operation, its flags and positional
293
- * arguments derived from the action's input. A field's flag shadows a global flag of the
294
- * same name; two flags of the command itself with one name are refused when it is built.
295
- * Input that does not decode is `InvalidInput`, as over HTTP, and the operation writes its
296
- * logs and console output to stderr, since stdout carries the result. Every failure is a
297
- * `UserError`, encoded with the surface's `errors` too, such as a binding's.
298
- */
299
- const command = (action, execute, options, errors = []) => {
300
- const name = options?.name ?? kebab(action.name);
301
- const render = options?.render;
302
- const { flags, positional, decode } = inputConfig(action, options?.positional ?? [], options?.aliases ?? {});
303
- const failure = failureOf(action, errors);
304
- assertDistinct("flag", [
305
- ...Object.keys(flags).map((field) => [`--${kebab(field)}`, `field ${field}`]),
306
- ...render === void 0 ? [] : [["--json", "render's --json"]],
307
- ...Object.entries(options?.aliases ?? {}).flatMap(([field, alias]) => Predicate.isString(alias) ? [[`--${alias.replace(/^-+/, "")}`, `alias of field ${field}`]] : [])
308
- ], ([flag]) => flag, ([, claimant]) => claimant);
309
- const args = positional.map(({ param }) => param);
310
- const parsedFields = (input, values) => ({
311
- ...input,
312
- ...Object.fromEntries(positional.map(({ field }, index) => [field, values[index] ?? Option.none()]))
313
- });
314
- const run = (parsed, rendered) => decode(parsed).pipe(Effect.mapError(InvalidInput.fromSchemaError), Effect.flatMap(execute), Effect.catch(failure), Effect.flatMap((value) => output(action, value, rendered)), logToStderr, Effect.flatMap(Option.match({
315
- onNone: () => Effect.void,
316
- onSome: Console.log
317
- })));
318
- return (render === void 0 ? Command.make(name, {
319
- input: flags,
320
- args
321
- }, ({ input, args: values }) => run(parsedFields(input, values), void 0)) : Command.make(name, {
322
- input: flags,
323
- args,
324
- json: jsonFlag
325
- }, ({ input, args: values, json }) => run(parsedFields(input, values), json ? void 0 : render))).pipe(Command.withDescription(action.description));
326
- };
327
- //#endregion
328
- export { UserError, command, kebab };
@@ -1,25 +0,0 @@
1
- import { InvalidInput } from "./errors.mjs";
2
- import { inputOf } from "./call.mjs";
3
- import { Effect, Schema } from "effect";
4
- import { HttpApiClient } from "effect/http-api";
5
- //#region src/internal/client.ts
6
- /** Refuse an action a binding of `actions` does not hold, matched by identity. */
7
- const assertInBinding = (actions, action) => {
8
- if (!actions.includes(action)) throw new Error(`Action "${action.name}" is not in this HTTP binding`);
9
- };
10
- /**
11
- * Build the native client of a binding once and look up each action's method, taking the
12
- * action's input directly. Every binding API is a native `HttpApi` of one top-level
13
- * group built from `http.actions`, so each action has a native method of its name.
14
- */
15
- const methods = (http, options = {}) => Effect.map(HttpApiClient.make(http.api, options), (client) => {
16
- const native = client;
17
- return (action) => {
18
- const method = native[action.name];
19
- if (method === void 0) throw new Error(`No client method for ${action.name}`);
20
- const encode = Schema.encodeUnknownEffect(Schema.toCodecJson(action.input), { errors: "all" });
21
- return (...args) => inputOf(action, args).pipe(Effect.tap(encode), Effect.mapError(InvalidInput.fromSchemaError), Effect.flatMap((payload) => method({ payload })));
22
- };
23
- });
24
- //#endregion
25
- export { assertInBinding, methods };
@@ -1,77 +0,0 @@
1
- import { Clock, Console, Effect, Function, Predicate } from "effect";
2
- //#region src/internal/console.ts
3
- /**
4
- * The console of code whose program's stdout carries data: a stdio server's protocol, or a
5
- * CLI command's result. Every method writes through `console.error` alone, so every console
6
- * logger, `Console.log` and the default logger alike, leaves stdout intact, and so do
7
- * counters, timers and group labels, which Node's console prints on stdout. A counter or a
8
- * timer prints its label as given, never as a format, then its count or the milliseconds
9
- * since it started, read on `clock` and rounded to three decimals; a group prints its label
10
- * without indenting what follows, and `clear` clears nothing.
11
- */
12
- const stderrConsole = (console, clock) => {
13
- const counts = /* @__PURE__ */ new Map();
14
- const timers = /* @__PURE__ */ new Map();
15
- const write = (...args) => console.error(...args);
16
- const elapsed = (label, data) => {
17
- const start = timers.get(label);
18
- if (start !== void 0) {
19
- const millis = Number(clock.monotonicTimeNanosUnsafe() - start) / 1e6;
20
- write("%s: %sms", label, Number(millis.toFixed(3)), ...data);
21
- }
22
- };
23
- const labeled = (label, args) => {
24
- const [first, ...rest] = args;
25
- write(...Predicate.isString(first) ? [`${label}: ${first}`, ...rest] : [label, ...args]);
26
- };
27
- const group = (...label) => {
28
- if (label.some((part) => part !== void 0)) write(...label);
29
- };
30
- return {
31
- assert: (condition, ...args) => {
32
- if (!condition) labeled("Assertion failed", args);
33
- },
34
- clear: Function.constVoid,
35
- count: (label = "default") => {
36
- const count = (counts.get(label) ?? 0) + 1;
37
- counts.set(label, count);
38
- write("%s: %d", label, count);
39
- },
40
- countReset: (label = "default") => {
41
- counts.delete(label);
42
- },
43
- debug: write,
44
- dir: (item) => write("%O", item),
45
- dirxml: write,
46
- error: write,
47
- group,
48
- groupCollapsed: group,
49
- groupEnd: Function.constVoid,
50
- info: write,
51
- log: write,
52
- table: (data) => write(data),
53
- time: (label = "default") => {
54
- timers.set(label, clock.monotonicTimeNanosUnsafe());
55
- },
56
- timeEnd: (label = "default") => {
57
- elapsed(label, []);
58
- timers.delete(label);
59
- },
60
- timeLog: (label = "default", ...data) => elapsed(label, data),
61
- trace: (...args) => {
62
- const { stack = "" } = /* @__PURE__ */ new Error();
63
- const frames = stack.split("\n").slice(2).join("\n");
64
- labeled("Trace", args);
65
- if (frames !== "") write(frames);
66
- },
67
- warn: write
68
- };
69
- };
70
- /**
71
- * `effect` writing its console output and Effect logs to stderr alone, through the console
72
- * it runs with: for what a surface runs where stdout carries data, a stdio server's program
73
- * or a CLI command's builder, authorizer and handler.
74
- */
75
- const logToStderr = (effect) => Effect.provideServiceEffect(effect, Console.Console, Effect.zipWith(Effect.service(Console.Console), Effect.service(Clock.Clock), stderrConsole));
76
- //#endregion
77
- export { logToStderr };
@@ -1,13 +0,0 @@
1
- import { Action_d_exports, Errors } from "../Action.mjs";
2
- import { HttpServerResponse } from "effect/http";
3
- //#region src/internal/declared.d.ts
4
- /** The list an `error` option of type `G` stands for: one schema is a list of one. */
5
- type ListOf<G> = G extends Errors ? G : readonly [G];
6
- /**
7
- * The errors options `O` declare, as at run time: those `error` always gives, or, where it may
8
- * be absent, those it gives or none, so clients decode each that may arrive.
9
- */
10
- export type ErrorsOf<O> = O extends unknown ? "error" extends keyof O ? O extends {
11
- readonly error: infer G extends Errors | Errors[number];
12
- } ? ListOf<G> : ListOf<Extract<O["error" & keyof O], Errors | Errors[number]>> | [] : [] : never;
13
- //#endregion
@@ -1,34 +0,0 @@
1
- import { unsuspended } from "./actions.mjs";
2
- import { Schema, SchemaAST } from "effect";
3
- import { HttpServerResponse } from "effect/http";
4
- import { HttpApiSchema } from "effect/http-api";
5
- //#region src/internal/declared.ts
6
- /** The status an error schema states, as `HttpApi` reads it. */
7
- const statusOf = SchemaAST.resolveAt("httpApiStatus");
8
- /** The status a schema states, or the first one a suspension it wraps states. */
9
- const statusThrough = (ast) => statusOf(ast) ?? (SchemaAST.isSuspend(ast) ? statusThrough(ast.thunk()) : void 0);
10
- /**
11
- * The schemas an endpoint declares for one error, each with the status it is sent with. `HttpApi`
12
- * reads a status off each declared schema, never off a union's members nor through a suspension, so
13
- * a plain union without a status of its own declares each member, and a suspended error, as a
14
- * recursive one is written, without a status of its own states the status of what it suspends. An
15
- * error without a status is an outcome the action expects, not a server fault: it is sent as 422,
16
- * rather than `HttpApi`'s 500, which clients and proxies read as the server failing.
17
- */
18
- const declared = (error) => {
19
- const status = statusThrough(error.ast);
20
- if (status !== void 0) return [statusOf(error.ast) === void 0 ? HttpApiSchema.status(status)(error) : error];
21
- const resolved = unsuspended(error.ast);
22
- if (SchemaAST.isUnion(resolved) && resolved.checks === void 0 && resolved.encoding === void 0) return resolved.types.flatMap((member) => declared(Schema.make(member)));
23
- return [HttpApiSchema.status(422)(error)];
24
- };
25
- /**
26
- * `error` as an endpoint declaring `errors` sends it: its JSON, encoded by the first declared
27
- * schema that accepts it, with that schema's status. None for a value no schema accepts.
28
- */
29
- const declaredResponse = (errors, error) => {
30
- const schema = errors.flatMap(declared).find((each) => Schema.is(each)(error));
31
- return schema === void 0 ? void 0 : HttpServerResponse.jsonUnsafe(Schema.encodeUnknownSync(Schema.toCodecJson(schema))(error), { status: statusOf(schema.ast) ?? 422 });
32
- };
33
- //#endregion
34
- export { declared, declaredResponse };
@@ -1,14 +0,0 @@
1
- import "./implementation.mjs";
2
- import "./media.mjs";
3
- import "../Action.mjs";
4
- import { Schema } from "effect";
5
- import { McpProtocol } from "effect/ai";
6
- //#region src/internal/mcp.d.ts
7
- /** An MCP request's parameters: JSON, leaving out an `undefined` one, as a caller may. */
8
- export interface Params {
9
- readonly _meta?: {
10
- readonly [key: string]: Schema.Json;
11
- };
12
- readonly [key: string]: Schema.Json | undefined;
13
- }
14
- //#endregion
@@ -1,8 +0,0 @@
1
- import { Schema, SchemaAST } from "effect";
2
- //#region src/internal/media.d.ts
3
- /** An image, a media field's schema, as `Action.Image` exports it. */
4
- export declare const Image: Schema.Struct<{
5
- readonly data: Schema.Uint8Array;
6
- readonly mimeType: Schema.String;
7
- }>;
8
- //#endregion
@@ -1,26 +0,0 @@
1
- import { Schema } from "effect";
2
- //#region src/internal/media.ts
3
- /**
4
- * The annotation marking a media kind's schema, naming the MCP content block a value of it is
5
- * lifted into: `Action.Image`'s is `"image"`.
6
- */
7
- const mediaKey = "effect-actions/media";
8
- /** What every media kind holds: bytes, and their MIME type. */
9
- const Media = Schema.Struct({
10
- data: Schema.Uint8Array,
11
- mimeType: Schema.String
12
- });
13
- /** An image, a media field's schema, as `Action.Image` exports it. */
14
- const Image = Media.annotate({ [mediaKey]: "image" });
15
- /**
16
- * Whether `ast` is marked as media, read from its own annotations: a copy, such as an optional
17
- * key or one with checks added, keeps them, and so does one with an encoding of its own.
18
- */
19
- const isMarked = (ast) => ast.annotations?.[mediaKey] === "image";
20
- /**
21
- * The kind `ast` is, when its values are the media they encode to: marked, without an encoding
22
- * of its own, which would send its values as something else.
23
- */
24
- const kindOf = (ast) => isMarked(ast) && ast.encoding === void 0 ? "image" : void 0;
25
- //#endregion
26
- export { Image, Media, isMarked, kindOf };
@@ -1,67 +0,0 @@
1
- import { Refusal, statuses } from "./errors.mjs";
2
- import { Cause, Context, Effect, Exit, Option, Predicate, Ref, Schema } from "effect";
3
- import { HttpServerResponse } from "effect/http";
4
- //#region src/internal/refusal.ts
5
- /** An RFC 6750 error description: printable ASCII but `"` and `\`. */
6
- const description = /^[\x20\x21\x23-\x5B\x5D-\x7E]+$/;
7
- /**
8
- * An RFC 9110 challenge of `scheme` and the parameters given, each a quoted string whose `"`
9
- * and `\` are escaped: a metadata URL's query may hold a `\`.
10
- */
11
- const challenge = (scheme, parameters) => {
12
- const given = parameters.flatMap(([name, value]) => value === void 0 ? [] : [`${name}="${value.replace(/["\\]/g, "\\$&")}"`]);
13
- return given.length === 0 ? scheme : `${scheme} ${given.join(", ")}`;
14
- };
15
- /** An RFC 6750 `Bearer` challenge of the parameters given. */
16
- const bearer = (parameters) => challenge("Bearer", parameters);
17
- const encode = Schema.encodeSync(Refusal);
18
- /** Whether `error` is a built-in refusal, `Unauthenticated` or `Forbidden`. */
19
- const isRefusal = Schema.is(Refusal);
20
- /**
21
- * The RFC 6750 `insufficient_scope` challenge an OAuth client steps up on, for a `Forbidden`
22
- * naming scopes, naming the resource's metadata URL when there is one.
23
- */
24
- const insufficientScope = (error, metadataUrl) => Predicate.isTagged(error, "Forbidden") && error.scopes !== void 0 ? bearer([
25
- ["error", "insufficient_scope"],
26
- ["scope", error.scopes.join(" ")],
27
- ["resource_metadata", metadataUrl],
28
- ["error_description", description.test(error.message) ? error.message : void 0]
29
- ]) : void 0;
30
- /** A refusal as its JSON with its status alone, as a scheme no OAuth client acts on answers it. */
31
- const plain = (error) => HttpServerResponse.jsonUnsafe(encode(error), { status: statuses[error._tag] });
32
- /**
33
- * A refusal as its JSON with its status, as every endpoint declares it, and its
34
- * `insufficient_scope` challenge if it has one.
35
- */
36
- const answer = (error, metadataUrl) => {
37
- const response = plain(error);
38
- const scoped = insufficientScope(error, metadataUrl);
39
- return scoped === void 0 ? response : HttpServerResponse.setHeader(response, "www-authenticate", scoped);
40
- };
41
- /** The step-up refusal a tool's call under `answerStepUp` failed with, which answers its request. */
42
- var SteppedUp = class extends Context.Service()("effect-actions/SteppedUp") {};
43
- /**
44
- * Whether `error` is a refusal an OAuth client acts on: `Unauthenticated`, or `Forbidden`
45
- * naming scopes.
46
- */
47
- const isStepUp = (error) => isRefusal(error) && (!Predicate.isTagged(error, "Forbidden") || error.scopes !== void 0);
48
- /**
49
- * A protected MCP tool's `call`, whose step-up refusal answers the request under a Bearer
50
- * descriptor's `answerStepUp`. Elsewhere it is `call` as it is.
51
- */
52
- const recordStepUp = (call) => Effect.tapError(call, (error) => isStepUp(error) ? Effect.flatMap(Effect.serviceOption(SteppedUp), (slot) => Option.isSome(slot) ? Ref.set(slot.value, Option.some(error)) : Effect.void) : Effect.void);
53
- /**
54
- * An MCP request, answered with the step-up refusal a tool's call in it failed with, its
55
- * status, JSON and challenge naming `metadataUrl`, however the request ended short of a defect
56
- * or an interruption: a tool's failure is a successful result, and MCP authorization requires
57
- * 401 or 403.
58
- */
59
- const answerStepUp = (route, metadataUrl) => Effect.gen(function* () {
60
- const slot = yield* Ref.make(Option.none());
61
- const exit = yield* Effect.exit(Effect.provideService(route, SteppedUp, slot));
62
- const refused = yield* Ref.get(slot);
63
- const broken = Exit.isFailure(exit) && (Cause.hasDies(exit.cause) || Cause.hasInterrupts(exit.cause));
64
- return Option.isSome(refused) && !broken ? answer(refused.value, metadataUrl) : yield* exit;
65
- });
66
- //#endregion
67
- export { answer, answerStepUp, bearer, challenge, isRefusal, isStepUp, plain, recordStepUp };
@@ -1,20 +0,0 @@
1
- import { InvalidInput } from "./errors.mjs";
2
- import { Effect } from "effect";
3
- import { HttpApiMiddleware } from "effect/http-api";
4
- //#region src/internal/schema-errors.ts
5
- /**
6
- * `HttpApiBuilder` reports these kinds while encoding the handler's answer, after the
7
- * handler ran; every other kind (`Payload`, `Params`, `Headers`, `Query`) comes from
8
- * decoding the request before it.
9
- */
10
- const responseKinds = /* @__PURE__ */ new Set(["Body", "ResponseHeaders"]);
11
- /**
12
- * The native middleware answering schema failures: a request that does not decode with
13
- * `InvalidInput`, the schema's own message and issues. A result that does not encode stays the
14
- * native failure, which Effect answers with an empty 500 and reports.
15
- */
16
- var SchemaErrors = class extends HttpApiMiddleware.Service()("effect-actions/http/SchemaErrors", { error: [InvalidInput] }) {};
17
- /** `SchemaErrors`' server side, built by `ActionHttp.layer` alone, so a client's bundle leaves it out. */
18
- const schemaErrors = () => HttpApiMiddleware.layerSchemaErrorTransform(SchemaErrors, (failure) => Effect.fail(responseKinds.has(failure.kind) ? failure : InvalidInput.fromSchemaError(failure.cause)));
19
- //#endregion
20
- export { SchemaErrors, schemaErrors };