effect 4.0.0-beta.104 → 4.0.0-beta.106

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 (300) hide show
  1. package/AGENTS.md +381 -0
  2. package/CLAUDE.md +381 -0
  3. package/ai-docs/README.md +44 -0
  4. package/ai-docs/package.json +36 -0
  5. package/ai-docs/src/01_effect/01_basics/01_effect-gen.ts +30 -0
  6. package/ai-docs/src/01_effect/01_basics/02_effect-fn.ts +39 -0
  7. package/ai-docs/src/01_effect/01_basics/10_creating-effects.ts +74 -0
  8. package/ai-docs/src/01_effect/01_basics/index.md +5 -0
  9. package/ai-docs/src/01_effect/02_schema/10_schema-basics.ts +43 -0
  10. package/ai-docs/src/01_effect/02_schema/index.md +7 -0
  11. package/ai-docs/src/01_effect/03_services/01_service.ts +45 -0
  12. package/ai-docs/src/01_effect/03_services/10_reference.ts +10 -0
  13. package/ai-docs/src/01_effect/03_services/20_layer-composition.ts +70 -0
  14. package/ai-docs/src/01_effect/03_services/20_layer-unwrap.ts +66 -0
  15. package/ai-docs/src/01_effect/03_services/index.md +5 -0
  16. package/ai-docs/src/01_effect/04_errors/01_error-handling.ts +30 -0
  17. package/ai-docs/src/01_effect/04_errors/10_catch-tags.ts +24 -0
  18. package/ai-docs/src/01_effect/04_errors/20_reason-errors.ts +64 -0
  19. package/ai-docs/src/01_effect/04_errors/index.md +1 -0
  20. package/ai-docs/src/01_effect/05_resources/10_acquire-release.ts +105 -0
  21. package/ai-docs/src/01_effect/05_resources/20_layer-side-effects.ts +31 -0
  22. package/ai-docs/src/01_effect/05_resources/30_layer-map.ts +86 -0
  23. package/ai-docs/src/01_effect/05_resources/index.md +3 -0
  24. package/ai-docs/src/01_effect/06_running/10_run-main.ts +30 -0
  25. package/ai-docs/src/01_effect/06_running/20_layer-launch.ts +27 -0
  26. package/ai-docs/src/01_effect/06_running/index.md +1 -0
  27. package/ai-docs/src/01_effect/07_pubsub/10_pubsub.ts +56 -0
  28. package/ai-docs/src/01_effect/07_pubsub/index.md +3 -0
  29. package/ai-docs/src/03_stream/10_creating-streams.ts +103 -0
  30. package/ai-docs/src/03_stream/20_consuming-streams.ts +137 -0
  31. package/ai-docs/src/03_stream/30_encoding.ts +165 -0
  32. package/ai-docs/src/03_stream/index.md +4 -0
  33. package/ai-docs/src/04_integration/10_managed-runtime.ts +129 -0
  34. package/ai-docs/src/04_integration/index.md +5 -0
  35. package/ai-docs/src/05_batching/10_request-resolver.ts +89 -0
  36. package/ai-docs/src/05_batching/index.md +3 -0
  37. package/ai-docs/src/06_schedule/10_schedules.ts +110 -0
  38. package/ai-docs/src/06_schedule/index.md +3 -0
  39. package/ai-docs/src/07_datetime/10_creating-and-formatting.ts +30 -0
  40. package/ai-docs/src/07_datetime/20_time-zones.ts +44 -0
  41. package/ai-docs/src/07_datetime/index.md +5 -0
  42. package/ai-docs/src/08_observability/10_logging.ts +66 -0
  43. package/ai-docs/src/08_observability/20_otlp-tracing.ts +95 -0
  44. package/ai-docs/src/08_observability/index.md +7 -0
  45. package/ai-docs/src/09_testing/10_effect-tests.ts +55 -0
  46. package/ai-docs/src/09_testing/20_layer-tests.ts +138 -0
  47. package/ai-docs/src/09_testing/index.md +1 -0
  48. package/ai-docs/src/10_predicate/01_basics.ts +14 -0
  49. package/ai-docs/src/10_predicate/index.md +9 -0
  50. package/ai-docs/src/50_http-client/10_basics.ts +102 -0
  51. package/ai-docs/src/50_http-client/index.md +3 -0
  52. package/ai-docs/src/51_http-server/10_basics.ts +116 -0
  53. package/ai-docs/src/51_http-server/fixtures/api/Api.ts +14 -0
  54. package/ai-docs/src/51_http-server/fixtures/api/Authorization.ts +36 -0
  55. package/ai-docs/src/51_http-server/fixtures/api/System.ts +10 -0
  56. package/ai-docs/src/51_http-server/fixtures/api/Users.ts +91 -0
  57. package/ai-docs/src/51_http-server/fixtures/domain/User.ts +12 -0
  58. package/ai-docs/src/51_http-server/fixtures/domain/UserErrors.ts +22 -0
  59. package/ai-docs/src/51_http-server/fixtures/server/Authorization.ts +36 -0
  60. package/ai-docs/src/51_http-server/fixtures/server/Users/http.ts +71 -0
  61. package/ai-docs/src/51_http-server/fixtures/server/Users.ts +62 -0
  62. package/ai-docs/src/51_http-server/index.md +3 -0
  63. package/ai-docs/src/60_child-process/10_working-with-child-processes.ts +117 -0
  64. package/ai-docs/src/60_child-process/index.md +3 -0
  65. package/ai-docs/src/70_cli/10_basics.ts +136 -0
  66. package/ai-docs/src/70_cli/index.md +5 -0
  67. package/ai-docs/src/71_ai/10_language-model.ts +156 -0
  68. package/ai-docs/src/71_ai/20_tools.ts +226 -0
  69. package/ai-docs/src/71_ai/30_chat.ts +158 -0
  70. package/ai-docs/src/71_ai/fixtures/domain/LaunchPlan.ts +9 -0
  71. package/ai-docs/src/71_ai/index.md +5 -0
  72. package/ai-docs/src/80_cluster/10_entities.ts +97 -0
  73. package/ai-docs/src/80_cluster/index.md +4 -0
  74. package/ai-docs/src/index.md +10 -0
  75. package/ai-docs/tsconfig.json +24 -0
  76. package/dist/Brand.d.ts +3 -3
  77. package/dist/Brand.d.ts.map +1 -1
  78. package/dist/Brand.js +4 -3
  79. package/dist/Brand.js.map +1 -1
  80. package/dist/Config.d.ts.map +1 -1
  81. package/dist/Config.js +5 -4
  82. package/dist/Config.js.map +1 -1
  83. package/dist/ConfigProvider.d.ts +35 -3
  84. package/dist/ConfigProvider.d.ts.map +1 -1
  85. package/dist/ConfigProvider.js +41 -8
  86. package/dist/ConfigProvider.js.map +1 -1
  87. package/dist/Context.d.ts +0 -1
  88. package/dist/Context.d.ts.map +1 -1
  89. package/dist/Context.js +1 -22
  90. package/dist/Context.js.map +1 -1
  91. package/dist/Cron.d.ts +31 -0
  92. package/dist/Cron.d.ts.map +1 -1
  93. package/dist/Cron.js +58 -2
  94. package/dist/Cron.js.map +1 -1
  95. package/dist/Fiber.d.ts +1 -1
  96. package/dist/Fiber.d.ts.map +1 -1
  97. package/dist/Function.d.ts +26 -0
  98. package/dist/Function.d.ts.map +1 -1
  99. package/dist/Function.js +36 -0
  100. package/dist/Function.js.map +1 -1
  101. package/dist/JsonSchema.d.ts.map +1 -1
  102. package/dist/JsonSchema.js +34 -17
  103. package/dist/JsonSchema.js.map +1 -1
  104. package/dist/Optic.d.ts +35 -21
  105. package/dist/Optic.d.ts.map +1 -1
  106. package/dist/Optic.js +33 -34
  107. package/dist/Optic.js.map +1 -1
  108. package/dist/Schema.d.ts +105 -109
  109. package/dist/Schema.d.ts.map +1 -1
  110. package/dist/Schema.js +141 -104
  111. package/dist/Schema.js.map +1 -1
  112. package/dist/SchemaAST.d.ts +32 -17
  113. package/dist/SchemaAST.d.ts.map +1 -1
  114. package/dist/SchemaAST.js +79 -60
  115. package/dist/SchemaAST.js.map +1 -1
  116. package/dist/SchemaError.d.ts +8 -8
  117. package/dist/SchemaError.d.ts.map +1 -1
  118. package/dist/SchemaError.js +7 -6
  119. package/dist/SchemaError.js.map +1 -1
  120. package/dist/SchemaGetter.d.ts +8 -5
  121. package/dist/SchemaGetter.d.ts.map +1 -1
  122. package/dist/SchemaGetter.js +41 -37
  123. package/dist/SchemaGetter.js.map +1 -1
  124. package/dist/SchemaIssue.d.ts +195 -38
  125. package/dist/SchemaIssue.d.ts.map +1 -1
  126. package/dist/SchemaIssue.js +243 -68
  127. package/dist/SchemaIssue.js.map +1 -1
  128. package/dist/SchemaParser.d.ts +30 -0
  129. package/dist/SchemaParser.d.ts.map +1 -1
  130. package/dist/SchemaParser.js +39 -9
  131. package/dist/SchemaParser.js.map +1 -1
  132. package/dist/SchemaRepresentation.d.ts +15 -3
  133. package/dist/SchemaRepresentation.d.ts.map +1 -1
  134. package/dist/SchemaRepresentation.js +8 -2
  135. package/dist/SchemaRepresentation.js.map +1 -1
  136. package/dist/SchemaTransformation.d.ts +2 -2
  137. package/dist/SchemaTransformation.d.ts.map +1 -1
  138. package/dist/SchemaTransformation.js +26 -26
  139. package/dist/SchemaTransformation.js.map +1 -1
  140. package/dist/ScopedRef.d.ts.map +1 -1
  141. package/dist/ScopedRef.js +1 -1
  142. package/dist/ScopedRef.js.map +1 -1
  143. package/dist/Stdio.d.ts +17 -4
  144. package/dist/Stdio.d.ts.map +1 -1
  145. package/dist/Stdio.js +6 -3
  146. package/dist/Stdio.js.map +1 -1
  147. package/dist/TxQueue.js +1 -1
  148. package/dist/TxQueue.js.map +1 -1
  149. package/dist/internal/effect.js +2 -4
  150. package/dist/internal/effect.js.map +1 -1
  151. package/dist/internal/executionPlan.js +3 -2
  152. package/dist/internal/executionPlan.js.map +1 -1
  153. package/dist/internal/rcRef.js +18 -13
  154. package/dist/internal/rcRef.js.map +1 -1
  155. package/dist/internal/schema/fromJsonSchemaDocument.js +10 -6
  156. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  157. package/dist/internal/schema/schema.js +1 -9
  158. package/dist/internal/schema/schema.js.map +1 -1
  159. package/dist/internal/schema/toArbitrary.d.ts +1 -4
  160. package/dist/internal/schema/toArbitrary.d.ts.map +1 -1
  161. package/dist/internal/schema/toArbitrary.js +0 -74
  162. package/dist/internal/schema/toArbitrary.js.map +1 -1
  163. package/dist/internal/schema/toJsonSchemaDocument.js +18 -4
  164. package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
  165. package/dist/internal/schema/toRepresentation.js +45 -43
  166. package/dist/internal/schema/toRepresentation.js.map +1 -1
  167. package/dist/testing/TestSchema.d.ts +1 -1
  168. package/dist/testing/TestSchema.d.ts.map +1 -1
  169. package/dist/testing/TestSchema.js +10 -9
  170. package/dist/testing/TestSchema.js.map +1 -1
  171. package/dist/unstable/ai/McpSchema.d.ts +110 -110
  172. package/dist/unstable/ai/McpSchema.d.ts.map +1 -1
  173. package/dist/unstable/ai/McpServer.d.ts.map +1 -1
  174. package/dist/unstable/ai/McpServer.js +23 -11
  175. package/dist/unstable/ai/McpServer.js.map +1 -1
  176. package/dist/unstable/ai/Prompt.d.ts +4 -3
  177. package/dist/unstable/ai/Prompt.d.ts.map +1 -1
  178. package/dist/unstable/ai/Prompt.js +42 -17
  179. package/dist/unstable/ai/Prompt.js.map +1 -1
  180. package/dist/unstable/cluster/Entity.d.ts +2 -2
  181. package/dist/unstable/cluster/Entity.d.ts.map +1 -1
  182. package/dist/unstable/cluster/Entity.js.map +1 -1
  183. package/dist/unstable/cluster/EntityProxy.d.ts +3 -3
  184. package/dist/unstable/cluster/EntityProxy.d.ts.map +1 -1
  185. package/dist/unstable/cluster/EntityProxy.js +4 -3
  186. package/dist/unstable/cluster/EntityProxy.js.map +1 -1
  187. package/dist/unstable/cluster/Reply.js +4 -4
  188. package/dist/unstable/cluster/Reply.js.map +1 -1
  189. package/dist/unstable/cluster/Sharding.d.ts +2 -2
  190. package/dist/unstable/cluster/Sharding.d.ts.map +1 -1
  191. package/dist/unstable/cluster/Sharding.js +14 -5
  192. package/dist/unstable/cluster/Sharding.js.map +1 -1
  193. package/dist/unstable/encoding/Msgpack.d.ts.map +1 -1
  194. package/dist/unstable/encoding/Msgpack.js +6 -6
  195. package/dist/unstable/encoding/Msgpack.js.map +1 -1
  196. package/dist/unstable/eventlog/EventLogEncryption.d.ts +6 -5
  197. package/dist/unstable/eventlog/EventLogEncryption.d.ts.map +1 -1
  198. package/dist/unstable/eventlog/EventLogEncryption.js +14 -12
  199. package/dist/unstable/eventlog/EventLogEncryption.js.map +1 -1
  200. package/dist/unstable/eventlog/EventLogMessage.d.ts +3 -3
  201. package/dist/unstable/eventlog/EventLogMessage.d.ts.map +1 -1
  202. package/dist/unstable/eventlog/EventLogMessage.js +2 -3
  203. package/dist/unstable/eventlog/EventLogMessage.js.map +1 -1
  204. package/dist/unstable/eventlog/EventLogRemote.js +4 -4
  205. package/dist/unstable/eventlog/EventLogRemote.js.map +1 -1
  206. package/dist/unstable/eventlog/EventLogServerEncrypted.js +3 -2
  207. package/dist/unstable/eventlog/EventLogServerEncrypted.js.map +1 -1
  208. package/dist/unstable/http/HttpClient.d.ts +59 -3
  209. package/dist/unstable/http/HttpClient.d.ts.map +1 -1
  210. package/dist/unstable/http/HttpClient.js +33 -19
  211. package/dist/unstable/http/HttpClient.js.map +1 -1
  212. package/dist/unstable/http/HttpServerRequest.d.ts.map +1 -1
  213. package/dist/unstable/http/HttpServerRequest.js +7 -1
  214. package/dist/unstable/http/HttpServerRequest.js.map +1 -1
  215. package/dist/unstable/http/MultipartParser/internal/multipart.d.ts.map +1 -1
  216. package/dist/unstable/http/MultipartParser/internal/multipart.js +18 -6
  217. package/dist/unstable/http/MultipartParser/internal/multipart.js.map +1 -1
  218. package/dist/unstable/httpapi/HttpApiBuilder.js +10 -10
  219. package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
  220. package/dist/unstable/httpapi/HttpApiClient.js +9 -9
  221. package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
  222. package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
  223. package/dist/unstable/httpapi/OpenApi.js +1 -1
  224. package/dist/unstable/httpapi/OpenApi.js.map +1 -1
  225. package/dist/unstable/reactivity/AsyncResult.d.ts.map +1 -1
  226. package/dist/unstable/reactivity/AsyncResult.js +4 -4
  227. package/dist/unstable/reactivity/AsyncResult.js.map +1 -1
  228. package/dist/unstable/reactivity/Atom.d.ts +26 -11
  229. package/dist/unstable/reactivity/Atom.d.ts.map +1 -1
  230. package/dist/unstable/reactivity/Atom.js +9 -22
  231. package/dist/unstable/reactivity/Atom.js.map +1 -1
  232. package/dist/unstable/rpc/RpcClient.d.ts.map +1 -1
  233. package/dist/unstable/rpc/RpcClient.js +8 -1
  234. package/dist/unstable/rpc/RpcClient.js.map +1 -1
  235. package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
  236. package/dist/unstable/rpc/RpcServer.js +3 -2
  237. package/dist/unstable/rpc/RpcServer.js.map +1 -1
  238. package/dist/unstable/sql/SqlResolver.d.ts.map +1 -1
  239. package/dist/unstable/sql/SqlResolver.js +20 -16
  240. package/dist/unstable/sql/SqlResolver.js.map +1 -1
  241. package/dist/unstable/workers/Worker.d.ts.map +1 -1
  242. package/dist/unstable/workers/Worker.js +11 -12
  243. package/dist/unstable/workers/Worker.js.map +1 -1
  244. package/dist/unstable/workflow/Workflow.d.ts.map +1 -1
  245. package/dist/unstable/workflow/Workflow.js +2 -2
  246. package/dist/unstable/workflow/Workflow.js.map +1 -1
  247. package/package.json +5 -2
  248. package/src/Brand.ts +4 -4
  249. package/src/Config.ts +6 -4
  250. package/src/ConfigProvider.ts +43 -8
  251. package/src/Context.ts +1 -23
  252. package/src/Cron.ts +65 -2
  253. package/src/Fiber.ts +1 -1
  254. package/src/Function.ts +37 -0
  255. package/src/JsonSchema.ts +43 -42
  256. package/src/Optic.ts +59 -58
  257. package/src/Schema.ts +213 -217
  258. package/src/SchemaAST.ts +135 -78
  259. package/src/SchemaError.ts +9 -9
  260. package/src/SchemaGetter.ts +89 -30
  261. package/src/SchemaIssue.ts +285 -80
  262. package/src/SchemaParser.ts +51 -17
  263. package/src/SchemaRepresentation.ts +15 -3
  264. package/src/SchemaTransformation.ts +66 -18
  265. package/src/ScopedRef.ts +3 -1
  266. package/src/Stdio.ts +23 -4
  267. package/src/TxQueue.ts +1 -1
  268. package/src/internal/effect.ts +3 -6
  269. package/src/internal/executionPlan.ts +3 -2
  270. package/src/internal/rcRef.ts +24 -16
  271. package/src/internal/schema/fromJsonSchemaDocument.ts +19 -14
  272. package/src/internal/schema/schema.ts +1 -17
  273. package/src/internal/schema/toArbitrary.ts +0 -72
  274. package/src/internal/schema/toJsonSchemaDocument.ts +24 -4
  275. package/src/internal/schema/toRepresentation.ts +66 -48
  276. package/src/testing/TestSchema.ts +10 -10
  277. package/src/unstable/ai/McpServer.ts +23 -11
  278. package/src/unstable/ai/Prompt.ts +51 -19
  279. package/src/unstable/cluster/Entity.ts +7 -2
  280. package/src/unstable/cluster/EntityProxy.ts +12 -5
  281. package/src/unstable/cluster/Reply.ts +4 -4
  282. package/src/unstable/cluster/Sharding.ts +29 -17
  283. package/src/unstable/encoding/Msgpack.ts +12 -8
  284. package/src/unstable/eventlog/EventLogEncryption.ts +15 -16
  285. package/src/unstable/eventlog/EventLogMessage.ts +2 -3
  286. package/src/unstable/eventlog/EventLogRemote.ts +4 -4
  287. package/src/unstable/eventlog/EventLogServerEncrypted.ts +2 -2
  288. package/src/unstable/http/HttpClient.ts +132 -23
  289. package/src/unstable/http/HttpServerRequest.ts +8 -3
  290. package/src/unstable/http/MultipartParser/internal/multipart.ts +19 -6
  291. package/src/unstable/httpapi/HttpApiBuilder.ts +32 -13
  292. package/src/unstable/httpapi/HttpApiClient.ts +26 -8
  293. package/src/unstable/httpapi/OpenApi.ts +4 -1
  294. package/src/unstable/reactivity/AsyncResult.ts +11 -6
  295. package/src/unstable/reactivity/Atom.ts +44 -25
  296. package/src/unstable/rpc/RpcClient.ts +9 -1
  297. package/src/unstable/rpc/RpcServer.ts +4 -2
  298. package/src/unstable/sql/SqlResolver.ts +28 -20
  299. package/src/unstable/workers/Worker.ts +13 -14
  300. package/src/unstable/workflow/Workflow.ts +2 -5
@@ -11,8 +11,9 @@
11
11
  */
12
12
  import type { StandardSchemaV1 } from "@standard-schema/spec"
13
13
  import * as Arr from "./Array.ts"
14
- import { formatPath, type Formatter as FormatterI } from "./Formatter.ts"
14
+ import { format, formatPath, type Formatter as FormatterI } from "./Formatter.ts"
15
15
  import * as InternalAnnotations from "./internal/schema/annotations.ts"
16
+ import * as InternalParser from "./internal/schema/parser.ts"
16
17
  import { hasProperty } from "./Predicate.ts"
17
18
  import type * as Schema from "./Schema.ts"
18
19
  import type * as SchemaAST from "./SchemaAST.ts"
@@ -51,6 +52,39 @@ export function isIssue(u: unknown): u is Issue {
51
52
  return hasProperty(u, TypeId) && u[TypeId] === TypeId
52
53
  }
53
54
 
55
+ /**
56
+ * Returns `true` when an issue contains an input reported by the schema parser.
57
+ *
58
+ * **When to use**
59
+ *
60
+ * Use when reading `Issue.input`, especially when `undefined` is a valid input
61
+ * value.
62
+ *
63
+ * **Details**
64
+ *
65
+ * Reported input is stored as an own property. This guard checks for that
66
+ * property and narrows `input` from optional to required.
67
+ *
68
+ * **Example** (Reading a reported input)
69
+ *
70
+ * ```ts import.meta.vitest
71
+ * import { Result, Schema, SchemaIssue } from "effect"
72
+ *
73
+ * const result = Schema.decodeUnknownResult(Schema.String)(1, { reportInput: true })
74
+ * if (Result.isFailure(result) && SchemaIssue.hasInput(result.failure.issue)) {
75
+ * result.failure.issue.input // => 1
76
+ * }
77
+ * ```
78
+ *
79
+ * @see {@link Issue} for the complete issue model
80
+ *
81
+ * @category guards
82
+ * @since 4.0.0
83
+ */
84
+ export function hasInput(issue: Issue): issue is Issue & { readonly input: unknown } {
85
+ return Object.hasOwn(issue, "input")
86
+ }
87
+
54
88
  /**
55
89
  * Union of all terminal (leaf) issue types that have no inner `Issue` children.
56
90
  *
@@ -91,15 +125,17 @@ export type Leaf =
91
125
  * Every node has a `_tag` field for pattern-matching. The union includes both
92
126
  * terminal {@link Leaf} types and composite types that wrap inner issues:
93
127
  * {@link Filter}, {@link Encoding}, {@link Pointer}, {@link Composite},
94
- * {@link AnyOf}. All `Issue` instances have a `toString()` that delegates to
95
- * the default formatter, so `String(issue)` produces a human-readable message.
96
- * Built-in issues have no `actual` field, and built-in messages do not include
97
- * the rejected value. This is not a general sanitization boundary: paths,
98
- * ASTs, union successes, and custom annotations or messages are preserved as
99
- * supplied and remain the caller's responsibility.
128
+ * {@link AnyOf}. Use {@link makeFormatterDefault} when a human-readable
129
+ * representation is needed. When parsing with `reportInput: true`,
130
+ * value-bearing issues expose the rejected value through an enumerable `input`
131
+ * field. Built-in formatters may include reported input in default messages. This
132
+ * is not a general sanitization boundary: paths, ASTs, union successes, and
133
+ * custom annotations or messages are preserved as supplied and remain the
134
+ * caller's responsibility.
100
135
  *
101
136
  * @see {@link Leaf} — the terminal subset
102
137
  * @see {@link isIssue} — type guard
138
+ * @see {@link hasInput} — checks whether an issue reports an input
103
139
  * @category models
104
140
  * @since 4.0.0
105
141
  */
@@ -114,8 +150,15 @@ export type Issue =
114
150
 
115
151
  class Base {
116
152
  readonly [TypeId] = TypeId
117
- toString(this: Issue): string {
118
- return defaultFormatter(this)
153
+ /**
154
+ * The input reported by the schema parser, when input reporting is enabled
155
+ * and the issue is associated with a present value.
156
+ */
157
+ declare readonly input?: unknown
158
+ constructor(input?: unknown, options?: SchemaAST.ParseOptions) {
159
+ if (options?.reportInput === true && input !== InternalParser.missing) {
160
+ this.input = input
161
+ }
119
162
  }
120
163
  }
121
164
 
@@ -137,11 +180,13 @@ class Base {
137
180
  * ```ts import.meta.vitest
138
181
  * import { SchemaAST, SchemaIssue } from "effect"
139
182
  *
183
+ * const formatIssue = SchemaIssue.makeFormatterDefault()
184
+ *
140
185
  * function describe(issue: SchemaIssue.Issue): string {
141
186
  * if (issue._tag === "Filter") {
142
- * return `Filter failed: ${String(issue.issue)}`
187
+ * return `Filter failed: ${formatIssue(issue.issue)}`
143
188
  * }
144
- * return String(issue)
189
+ * return formatIssue(issue)
145
190
  * }
146
191
  *
147
192
  * const issue = new SchemaIssue.Filter(
@@ -176,9 +221,18 @@ export class Filter extends Base {
176
221
  /**
177
222
  * The issue that occurred.
178
223
  */
179
- issue: Issue
224
+ issue: Issue,
225
+ /**
226
+ * The present input associated with the issue. It is retained only when
227
+ * `options.reportInput` is `true`.
228
+ */
229
+ input?: unknown,
230
+ /**
231
+ * The effective parse options controlling input retention.
232
+ */
233
+ options?: SchemaAST.ParseOptions
180
234
  ) {
181
- super()
235
+ super(input, options)
182
236
  this.filter = filter
183
237
  this.issue = issue
184
238
  }
@@ -222,9 +276,18 @@ export class Encoding extends Base {
222
276
  /**
223
277
  * The issue that occurred.
224
278
  */
225
- issue: Issue
279
+ issue: Issue,
280
+ /**
281
+ * The present input associated with the issue. It is retained only when
282
+ * `options.reportInput` is `true`.
283
+ */
284
+ input?: unknown,
285
+ /**
286
+ * The effective parse options controlling input retention.
287
+ */
288
+ options?: SchemaAST.ParseOptions
226
289
  ) {
227
- super()
290
+ super(input, options)
228
291
  this.ast = ast
229
292
  this.issue = issue
230
293
  }
@@ -325,7 +388,8 @@ export class MissingKey extends Base {
325
388
  *
326
389
  * - `ast` is the schema that was being validated against.
327
390
  * - `annotations` on `ast` may contain a custom `messageUnexpectedKey`.
328
- * - The default formatter renders this as `"Expected no excess property"`.
391
+ * - The default formatter renders this as `"Expected no excess property"`, or
392
+ * `"Unexpected key with value <input>"` when the issue reports an input.
329
393
  *
330
394
  * @see {@link MissingKey} — the opposite case (required key absent)
331
395
  * @see {@link Pointer} — wraps this issue with the unexpected key's path
@@ -343,9 +407,18 @@ export class UnexpectedKey extends Base {
343
407
  /**
344
408
  * The schema that caused the issue.
345
409
  */
346
- ast: SchemaAST.AST
410
+ ast: SchemaAST.AST,
411
+ /**
412
+ * The present input associated with the issue. It is retained only when
413
+ * `options.reportInput` is `true`.
414
+ */
415
+ input?: unknown,
416
+ /**
417
+ * The effective parse options controlling input retention.
418
+ */
419
+ options?: SchemaAST.ParseOptions
347
420
  ) {
348
- super()
421
+ super(input, options)
349
422
  this.ast = ast
350
423
  }
351
424
  }
@@ -388,9 +461,18 @@ export class Composite extends Base {
388
461
  /**
389
462
  * The issues that occurred.
390
463
  */
391
- issues: readonly [Issue, ...Array<Issue>]
464
+ issues: readonly [Issue, ...Array<Issue>],
465
+ /**
466
+ * The present input associated with the issue. It is retained only when
467
+ * `options.reportInput` is `true`.
468
+ */
469
+ input?: unknown,
470
+ /**
471
+ * The effective parse options controlling input retention.
472
+ */
473
+ options?: SchemaAST.ParseOptions
392
474
  ) {
393
- super()
475
+ super(input, options)
394
476
  this.ast = ast
395
477
  this.issues = issues
396
478
  }
@@ -408,15 +490,17 @@ export class Composite extends Base {
408
490
  * **Details**
409
491
  *
410
492
  * - `ast` is the schema node that expected a different type.
411
- * - The default formatter renders this as `"Expected <type>"`.
493
+ * - The default formatter renders this as `"Expected <type>"`, adding
494
+ * `", got <input>"` when the issue reports an input.
412
495
  *
413
496
  * **Example** (Formatting a type mismatch)
414
497
  *
415
498
  * ```ts import.meta.vitest
416
499
  * import { Schema, SchemaIssue } from "effect"
417
500
  *
501
+ * const formatIssue = SchemaIssue.makeFormatterDefault()
418
502
  * const issue = new SchemaIssue.InvalidType(Schema.String.ast)
419
- * String(issue) // => "Expected string"
503
+ * formatIssue(issue) // => "Expected string"
420
504
  * ```
421
505
  *
422
506
  * @see {@link InvalidValue} — the input has the right type but fails a value constraint
@@ -434,9 +518,18 @@ export class InvalidType extends Base {
434
518
  /**
435
519
  * The schema that caused the issue.
436
520
  */
437
- ast: SchemaAST.AST
521
+ ast: SchemaAST.AST,
522
+ /**
523
+ * The present input associated with the issue. It is retained only when
524
+ * `options.reportInput` is `true`.
525
+ */
526
+ input?: unknown,
527
+ /**
528
+ * The effective parse options controlling input retention.
529
+ */
530
+ options?: SchemaAST.ParseOptions
438
531
  ) {
439
- super()
532
+ super(input, options)
440
533
  this.ast = ast
441
534
  }
442
535
  }
@@ -452,17 +545,22 @@ export class InvalidType extends Base {
452
545
  *
453
546
  * **Details**
454
547
  *
455
- * - `annotations` optionally carries a `message` string for formatting.
456
- * - The default formatter renders this as `"Expected a valid value"` unless a
457
- * custom `message` annotation is provided.
548
+ * - A `message` annotation is returned unchanged and takes precedence over all
549
+ * other default formatting.
550
+ * - Without `message`, an `expected` annotation is formatted as
551
+ * `"Expected <expected>"`, adding `", got <input>"` when input is reported.
552
+ * - Without either annotation, the default formatter renders
553
+ * `"Expected a valid value"`, or `"Invalid data <input>"` when input is
554
+ * reported.
458
555
  *
459
556
  * **Example** (Returning InvalidValue from a custom filter)
460
557
  *
461
558
  * ```ts import.meta.vitest
462
559
  * import { SchemaIssue } from "effect"
463
560
  *
561
+ * const formatIssue = SchemaIssue.makeFormatterDefault()
464
562
  * const issue = new SchemaIssue.InvalidValue({ message: "must not be empty" })
465
- * String(issue) // => "must not be empty"
563
+ * formatIssue(issue) // => "must not be empty"
466
564
  * ```
467
565
  *
468
566
  * @see {@link InvalidType} — the input has the wrong type entirely
@@ -479,13 +577,41 @@ export class InvalidValue extends Base {
479
577
  readonly annotations: Schema.Annotations.Issue | undefined
480
578
 
481
579
  constructor(
482
- annotations?: Schema.Annotations.Issue | undefined
580
+ /**
581
+ * The metadata for the issue.
582
+ */
583
+ annotations?: Schema.Annotations.Issue | undefined,
584
+ /**
585
+ * The present input associated with the issue. It is retained only when
586
+ * `options.reportInput` is `true`.
587
+ */
588
+ input?: unknown,
589
+ /**
590
+ * The effective parse options controlling input retention.
591
+ */
592
+ options?: SchemaAST.ParseOptions
483
593
  ) {
484
- super()
594
+ super(input, options)
485
595
  this.annotations = annotations
486
596
  }
487
597
  }
488
598
 
599
+ /** @internal */
600
+ export function makeCompositeAtKey(
601
+ compositeAst: SchemaAST.AST,
602
+ pointerKey: PropertyKey,
603
+ pointerIssue: Issue,
604
+ compositeInput: unknown,
605
+ parseOptions?: SchemaAST.ParseOptions
606
+ ): Composite {
607
+ return new Composite(
608
+ compositeAst,
609
+ [new Pointer([pointerKey], pointerIssue)],
610
+ compositeInput,
611
+ parseOptions
612
+ )
613
+ }
614
+
489
615
  /**
490
616
  * Represents a schema issue produced when a forbidden operation is encountered during parsing,
491
617
  * such as an asynchronous Effect running inside `Schema.decodeUnknownSync`.
@@ -505,10 +631,11 @@ export class InvalidValue extends Base {
505
631
  * ```ts import.meta.vitest
506
632
  * import { SchemaIssue } from "effect"
507
633
  *
634
+ * const formatIssue = SchemaIssue.makeFormatterDefault()
508
635
  * const issue = new SchemaIssue.Forbidden(
509
636
  * { message: "async operation not allowed in sync context" }
510
637
  * )
511
- * String(issue) // => "async operation not allowed in sync context"
638
+ * formatIssue(issue) // => "async operation not allowed in sync context"
512
639
  * ```
513
640
  *
514
641
  * @see {@link InvalidValue} — for value-constraint failures (not operation failures)
@@ -527,9 +654,18 @@ export class Forbidden extends Base {
527
654
  /**
528
655
  * The metadata for the issue.
529
656
  */
530
- annotations: Schema.Annotations.Issue | undefined
657
+ annotations: Schema.Annotations.Issue | undefined,
658
+ /**
659
+ * The present input associated with the issue. It is retained only when
660
+ * `options.reportInput` is `true`.
661
+ */
662
+ input?: unknown,
663
+ /**
664
+ * The effective parse options controlling input retention.
665
+ */
666
+ options?: SchemaAST.ParseOptions
531
667
  ) {
532
- super()
668
+ super(input, options)
533
669
  this.annotations = annotations
534
670
  }
535
671
  }
@@ -550,7 +686,8 @@ export class Forbidden extends Base {
550
686
  * **Gotchas**
551
687
  *
552
688
  * `issues` is empty when no union member was applicable. In that case, the
553
- * default formatter reports the expected type for the union.
689
+ * default formatter reports the expected type for the union and appends
690
+ * `", got <input>"` when input is reported.
554
691
  *
555
692
  * @see {@link OneOf} — the opposite: *too many* members matched
556
693
  * @see {@link Composite} — groups multiple issues under a non-union schema
@@ -577,9 +714,18 @@ export class AnyOf extends Base {
577
714
  /**
578
715
  * The issues that occurred.
579
716
  */
580
- issues: ReadonlyArray<Issue>
717
+ issues: ReadonlyArray<Issue>,
718
+ /**
719
+ * The present input associated with the issue. It is retained only when
720
+ * `options.reportInput` is `true`.
721
+ */
722
+ input?: unknown,
723
+ /**
724
+ * The effective parse options controlling input retention.
725
+ */
726
+ options?: SchemaAST.ParseOptions
581
727
  ) {
582
- super()
728
+ super(input, options)
583
729
  this.ast = ast
584
730
  this.issues = issues
585
731
  }
@@ -599,7 +745,9 @@ export class AnyOf extends Base {
599
745
  * - `ast` is the `Union` AST node.
600
746
  * - `successes` lists the AST nodes of each member that accepted the input.
601
747
  * - The default formatter renders this as
602
- * `"Expected exactly one member to match"`.
748
+ * `"Expected exactly one member to match"`, or
749
+ * `"Expected exactly one member to match the input <input>"` when input is
750
+ * reported.
603
751
  *
604
752
  * @see {@link AnyOf} — the opposite: *no* members matched
605
753
  *
@@ -625,52 +773,71 @@ export class OneOf extends Base {
625
773
  /**
626
774
  * The schemas that were successful.
627
775
  */
628
- successes: ReadonlyArray<SchemaAST.AST>
776
+ successes: ReadonlyArray<SchemaAST.AST>,
777
+ /**
778
+ * The present input associated with the issue. It is retained only when
779
+ * `options.reportInput` is `true`.
780
+ */
781
+ input?: unknown,
782
+ /**
783
+ * The effective parse options controlling input retention.
784
+ */
785
+ options?: SchemaAST.ParseOptions
629
786
  ) {
630
- super()
787
+ super(input, options)
631
788
  this.ast = ast
632
789
  this.successes = successes
633
790
  }
634
791
  }
635
792
 
636
- function makeFilterIssue(entry: Schema.FilterIssue): Issue {
793
+ function makeFilterIssue(
794
+ entry: Schema.FilterIssue,
795
+ input?: unknown,
796
+ options?: SchemaAST.ParseOptions
797
+ ): Issue {
637
798
  if (isIssue(entry)) {
638
799
  return entry
639
800
  }
640
801
  if (typeof entry === "string") {
641
- return new InvalidValue({ message: entry })
802
+ return new InvalidValue({ message: entry }, input, options)
642
803
  }
643
804
  const inner = typeof entry.issue === "string"
644
- ? new InvalidValue({ message: entry.issue })
805
+ ? new InvalidValue({ message: entry.issue }, input, options)
645
806
  : entry.issue
646
807
  return new Pointer(entry.path, inner)
647
808
  }
648
809
 
649
810
  /** @internal */
650
- export function makeSingle(out: undefined | boolean | Schema.FilterIssue): Issue | undefined {
811
+ export function makeSingle(
812
+ out: undefined | boolean | Schema.FilterIssue,
813
+ input?: unknown,
814
+ options?: SchemaAST.ParseOptions
815
+ ): Issue | undefined {
651
816
  if (out === undefined) {
652
817
  return undefined
653
818
  }
654
819
  if (typeof out === "boolean") {
655
- return out ? undefined : new InvalidValue()
820
+ return out ? undefined : new InvalidValue(undefined, input, options)
656
821
  }
657
- return makeFilterIssue(out)
822
+ return makeFilterIssue(out, input, options)
658
823
  }
659
824
 
660
825
  /** @internal */
661
826
  export function normalizeFilterOutput(
662
827
  ast: SchemaAST.AST,
663
- out: Schema.FilterOutput
828
+ out: Schema.FilterOutput,
829
+ input?: unknown,
830
+ options?: SchemaAST.ParseOptions
664
831
  ): Issue | undefined {
665
832
  if (Array.isArray(out)) {
666
833
  if (!Arr.isReadonlyArrayNonEmpty(out)) {
667
834
  return undefined
668
835
  }
669
836
  return out.length === 1
670
- ? makeFilterIssue(out[0])
671
- : new Composite(ast, Arr.map(out, makeFilterIssue))
837
+ ? makeFilterIssue(out[0], input, options)
838
+ : new Composite(ast, Arr.map(out, (entry) => makeFilterIssue(entry, input, options)), input, options)
672
839
  }
673
- return makeSingle(out as undefined | boolean | Schema.FilterIssue)
840
+ return makeSingle(out as undefined | boolean | Schema.FilterIssue, input, options)
674
841
  }
675
842
 
676
843
  /**
@@ -712,13 +879,18 @@ export type LeafHook = (issue: Leaf) => string
712
879
  * **Details**
713
880
  *
714
881
  * - Checks for a `message` annotation first; returns it if present.
715
- * - Otherwise generates a default message per `_tag`:
716
- * - `InvalidType` `"Expected <type>"`
717
- * - `InvalidValue` `"Expected a valid value"`
882
+ * - For `InvalidValue`, an `expected` annotation uses the standard expected
883
+ * value message and includes reported input when available.
884
+ * - Otherwise generates a default message per `_tag`. When the issue reports
885
+ * input, the message includes its formatted value where applicable:
886
+ * - `InvalidType` → `"Expected <type>"` or `"Expected <type>, got <input>"`
887
+ * - `InvalidValue` → `"Expected a valid value"` or `"Invalid data <input>"`
718
888
  * - `MissingKey` → `"Missing key"`
719
- * - `UnexpectedKey` → `"Expected no excess property"`
889
+ * - `UnexpectedKey` → `"Expected no excess property"` or
890
+ * `"Unexpected key with value <input>"`
720
891
  * - `Forbidden` → `"Forbidden operation"`
721
- * - `OneOf` → `"Expected exactly one member to match"`
892
+ * - `OneOf` → `"Expected exactly one member to match"` or
893
+ * `"Expected exactly one member to match the input <input>"`
722
894
  *
723
895
  * **Example** (Formatting Standard Schema issues with defaultLeafHook)
724
896
  *
@@ -742,17 +914,27 @@ export const defaultLeafHook: LeafHook = (issue): string => {
742
914
  if (message !== undefined) return message
743
915
  switch (issue._tag) {
744
916
  case "InvalidType":
745
- return getExpectedMessage(InternalAnnotations.getExpected(issue.ast))
746
- case "InvalidValue":
747
- return "Expected a valid value"
917
+ return getExpectedMessage(InternalAnnotations.getExpected(issue.ast), issue)
918
+ case "InvalidValue": {
919
+ const expected = findExpected(issue)
920
+ if (expected !== undefined) return getExpectedMessage(expected, issue)
921
+ const input = formatInput(issue)
922
+ return input === undefined ? "Expected a valid value" : `Invalid data ${input}`
923
+ }
748
924
  case "MissingKey":
749
925
  return "Missing key"
750
- case "UnexpectedKey":
751
- return "Expected no excess property"
926
+ case "UnexpectedKey": {
927
+ const input = formatInput(issue)
928
+ return input === undefined ? "Expected no excess property" : `Unexpected key with value ${input}`
929
+ }
752
930
  case "Forbidden":
753
931
  return "Forbidden operation"
754
- case "OneOf":
755
- return "Expected exactly one member to match"
932
+ case "OneOf": {
933
+ const input = formatInput(issue)
934
+ return input === undefined
935
+ ? "Expected exactly one member to match"
936
+ : `Expected exactly one member to match the input ${input}`
937
+ }
756
938
  }
757
939
  }
758
940
 
@@ -768,8 +950,6 @@ export const defaultLeafHook: LeafHook = (issue): string => {
768
950
  *
769
951
  * - Returns `string` to override the message, or `undefined` to fall back to
770
952
  * the default formatting.
771
- * - Built-in issues have no `actual` field.
772
- *
773
953
  * @see {@link defaultCheckHook} — the built-in implementation
774
954
  * @see {@link Filter} — the issue type this hook formats
775
955
  *
@@ -790,7 +970,8 @@ export type CheckHook = (issue: Filter) => string | undefined
790
970
  * - Looks for a `message` annotation on the inner issue first, then on the
791
971
  * filter itself.
792
972
  * - Returns `undefined` when no annotation is found, causing the formatter to
793
- * fall back to `"Expected <filter>"`.
973
+ * fall back to `"Expected <filter>"` or, when the filter reports input,
974
+ * `"Expected <filter>, got <input>"`.
794
975
  *
795
976
  * @see {@link CheckHook}
796
977
  * @see {@link makeFormatterStandardSchemaV1}
@@ -798,9 +979,7 @@ export type CheckHook = (issue: Filter) => string | undefined
798
979
  * @category formatting
799
980
  * @since 4.0.0
800
981
  */
801
- export const defaultCheckHook: CheckHook = (issue): string | undefined => {
802
- return findMessage(issue.issue) ?? findMessage(issue)
803
- }
982
+ export const defaultCheckHook: CheckHook = (issue): string | undefined => findMessage(issue.issue) ?? findMessage(issue)
804
983
 
805
984
  /**
806
985
  * Creates a {@link Formatter} that produces a `StandardSchemaV1.FailureResult`.
@@ -818,6 +997,15 @@ export const defaultCheckHook: CheckHook = (issue): string | undefined => {
818
997
  * - `Pointer` paths are accumulated to produce full property paths.
819
998
  * - Falls back to {@link defaultLeafHook} / {@link defaultCheckHook} when no
820
999
  * hooks are provided.
1000
+ * - Default messages include reported input when the issue that produces the
1001
+ * message has an `input` field. The returned Standard Schema issues do not
1002
+ * receive an `input` field.
1003
+ *
1004
+ * **Gotchas**
1005
+ *
1006
+ * Reported input can appear inside the Standard Schema `message` string even
1007
+ * though it is not exposed as a separate property. Custom hooks control their
1008
+ * complete message and are not modified.
821
1009
  *
822
1010
  * **Example** (Creating a Standard Schema V1 formatter)
823
1011
  *
@@ -850,8 +1038,18 @@ type DefaultIssue = {
850
1038
  readonly path: ReadonlyArray<PropertyKey>
851
1039
  }
852
1040
 
853
- function getExpectedMessage(expected: string): string {
854
- return `Expected ${expected}`
1041
+ function formatInput(issue: Issue): string | undefined {
1042
+ return hasInput(issue) ? format(issue.input) : undefined
1043
+ }
1044
+
1045
+ function findExpected(issue: InvalidValue): string | undefined {
1046
+ const expected = issue.annotations?.expected
1047
+ return typeof expected === "string" ? expected : undefined
1048
+ }
1049
+
1050
+ function getExpectedMessage(expected: string, issue: Issue): string {
1051
+ const input = formatInput(issue)
1052
+ return input === undefined ? `Expected ${expected}` : `Expected ${expected}, got ${input}`
855
1053
  }
856
1054
 
857
1055
  function toDefaultIssues(
@@ -866,15 +1064,16 @@ function toDefaultIssues(
866
1064
  if (message !== undefined) {
867
1065
  return [{ path, message }]
868
1066
  }
869
- switch (issue.issue._tag) {
870
- case "InvalidValue":
871
- return [{
872
- path,
873
- message: getExpectedMessage(formatCheck(issue.filter))
874
- }]
875
- default:
876
- return toDefaultIssues(issue.issue, path, leafHook, checkHook)
1067
+ if (issue.issue._tag !== "InvalidValue") {
1068
+ return toDefaultIssues(issue.issue, path, leafHook, checkHook)
877
1069
  }
1070
+ const expected = findExpected(issue.issue)
1071
+ return [{
1072
+ path,
1073
+ message: expected === undefined
1074
+ ? getExpectedMessage(formatCheck(issue.filter), issue)
1075
+ : getExpectedMessage(expected, issue.issue)
1076
+ }]
878
1077
  }
879
1078
  case "Encoding":
880
1079
  return toDefaultIssues(issue.issue, path, leafHook, checkHook)
@@ -886,7 +1085,7 @@ function toDefaultIssues(
886
1085
  if (issue.issues.length === 0) {
887
1086
  return [{
888
1087
  path,
889
- message: findMessage(issue) ?? getExpectedMessage(InternalAnnotations.getExpected(issue.ast))
1088
+ message: findMessage(issue) ?? getExpectedMessage(InternalAnnotations.getExpected(issue.ast), issue)
890
1089
  }]
891
1090
  }
892
1091
  return issue.issues.flatMap((issue) => toDefaultIssues(issue, path, leafHook, checkHook))
@@ -919,13 +1118,19 @@ function formatCheck<T>(check: SchemaAST.Check<T>): string {
919
1118
  *
920
1119
  * **Details**
921
1120
  *
922
- * This is the default formatter used by `SchemaIssue.toString()`.
923
- *
924
1121
  * - Flattens the issue tree into `{ message, path }` entries using
925
1122
  * {@link defaultLeafHook} and {@link defaultCheckHook}.
1123
+ * - Includes reported input in default messages when the node producing the
1124
+ * message has an `input` field.
926
1125
  * - Each entry is rendered as `"<message>"` or `"<message>\n at <path>"`.
927
1126
  * - Multiple entries are joined with newlines.
928
1127
  *
1128
+ * **Gotchas**
1129
+ *
1130
+ * Formatting an issue can disclose input retained with `reportInput: true`.
1131
+ * Wrapper inputs are not inherited by child messages, and custom messages are
1132
+ * returned unchanged.
1133
+ *
929
1134
  * **Example** (Formatting an issue as a string)
930
1135
  *
931
1136
  * ```ts import.meta.vitest