@zio.dev/zio-blocks 0.0.33 → 0.0.55

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/adr/2026-07-18-data-migration.md +123 -0
  2. package/guides/async-getting-started.md +687 -0
  3. package/guides/compile-time-resource-safety-with-scope.md +21 -16
  4. package/guides/getting-started-with-mux.md +1395 -0
  5. package/guides/query-dsl-extending.md +161 -102
  6. package/guides/query-dsl-fluent-builder.md +217 -157
  7. package/guides/query-dsl-reified-optics.md +12 -10
  8. package/guides/query-dsl-sql.md +640 -165
  9. package/guides/sql-checked-interpolation.md +173 -0
  10. package/guides/sql-transactions.md +286 -0
  11. package/guides/telemetry-guide.md +1130 -0
  12. package/guides/zio-schema-migration.md +29 -22
  13. package/index.md +248 -389
  14. package/package.json +1 -1
  15. package/plans/config-follow-up-prs.md +188 -0
  16. package/plans/config-pr-assessment-roadmap.md +310 -0
  17. package/reference/MuxDataFlow.jsx +250 -0
  18. package/reference/async.md +1499 -0
  19. package/reference/chunk.md +3533 -308
  20. package/reference/codegen/case-class.md +436 -0
  21. package/reference/codegen/emitter-config.md +383 -0
  22. package/reference/codegen/examples.md +664 -0
  23. package/reference/codegen/field.md +316 -0
  24. package/reference/codegen/index.md +317 -0
  25. package/reference/codegen/scala-emitter.md +392 -0
  26. package/reference/codegen/scala-file.md +276 -0
  27. package/reference/codegen/sealed-trait.md +408 -0
  28. package/reference/codegen/type-definition.md +340 -0
  29. package/reference/codegen/type-ref.md +201 -0
  30. package/reference/combinators.md +347 -117
  31. package/reference/config/config-decoder.md +460 -0
  32. package/reference/config/config-source.md +489 -0
  33. package/reference/config/errors.md +278 -0
  34. package/reference/config/flags.md +369 -0
  35. package/reference/config/formats.md +314 -0
  36. package/reference/config/index.md +304 -0
  37. package/reference/config/rollout.md +336 -0
  38. package/reference/context.md +9 -52
  39. package/reference/data-migration.md +269 -0
  40. package/reference/datastar/attributes.md +302 -0
  41. package/reference/datastar/events.md +234 -0
  42. package/reference/datastar/index.md +256 -0
  43. package/reference/datastar/signals.md +230 -0
  44. package/reference/datastar/sse.md +295 -0
  45. package/reference/datastar.md +346 -0
  46. package/reference/docs.md +1461 -345
  47. package/reference/endpoint/auth-type.md +146 -0
  48. package/reference/endpoint/bulk-creation.md +96 -0
  49. package/reference/endpoint/endpoint.md +297 -0
  50. package/reference/endpoint/http-codec.md +249 -0
  51. package/reference/endpoint/index.md +745 -0
  52. package/reference/endpoint/path-codec.md +225 -0
  53. package/reference/endpoint/route-pattern.md +194 -0
  54. package/reference/endpoint/route-tree.md +111 -0
  55. package/reference/endpoint/segment-codec.md +199 -0
  56. package/reference/html.md +1424 -0
  57. package/reference/htmx/attribute-values.md +359 -0
  58. package/reference/htmx/hx-encoding.md +111 -0
  59. package/reference/htmx/hx-params.md +204 -0
  60. package/reference/htmx/hx-swap.md +276 -0
  61. package/reference/htmx/hx-sync.md +251 -0
  62. package/reference/htmx/hx-target.md +314 -0
  63. package/reference/htmx/hx-trigger.md +457 -0
  64. package/reference/htmx/hx-url-update.md +239 -0
  65. package/reference/htmx/index.md +807 -0
  66. package/reference/htmx/response-headers.md +240 -0
  67. package/reference/http-model/headers.md +735 -0
  68. package/reference/http-model/index.md +49 -0
  69. package/reference/http-model/model.md +1517 -0
  70. package/reference/http-model/schema-codecs.md +522 -0
  71. package/reference/http-model/schema.md +750 -0
  72. package/reference/http-model/server-sent-event.md +341 -0
  73. package/reference/jwt.md +195 -0
  74. package/reference/maybe.md +943 -0
  75. package/reference/media-type.md +2 -2
  76. package/reference/mux.md +254 -0
  77. package/reference/mux.mdx +828 -0
  78. package/reference/openapi.md +1351 -0
  79. package/reference/projection.md +654 -0
  80. package/reference/resource-management/defer-handle.md +1 -1
  81. package/reference/resource-management/resource.md +31 -98
  82. package/reference/resource-management/scope.md +28 -220
  83. package/reference/resource-management/wire.md +5 -55
  84. package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
  85. package/reference/ringbuffer/MpscDiagram.jsx +618 -0
  86. package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
  87. package/reference/ringbuffer/SpscDiagram.jsx +677 -0
  88. package/reference/ringbuffer/advanced.mdx +109 -0
  89. package/reference/ringbuffer/index.mdx +145 -0
  90. package/reference/ringbuffer/mpmc.mdx +185 -0
  91. package/reference/ringbuffer/mpsc.mdx +164 -0
  92. package/reference/ringbuffer/spmc.mdx +108 -0
  93. package/reference/ringbuffer/spsc.mdx +416 -0
  94. package/reference/{allows.md → schema/allows.md} +4 -100
  95. package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
  96. package/reference/{binding.md → schema/binding.md} +3 -4
  97. package/reference/schema/built-in-codecs/avro.md +451 -0
  98. package/reference/schema/built-in-codecs/bson.md +510 -0
  99. package/reference/schema/built-in-codecs/csv.md +564 -0
  100. package/reference/schema/built-in-codecs/index.md +77 -0
  101. package/reference/schema/built-in-codecs/json/index.md +295 -0
  102. package/reference/schema/built-in-codecs/json/json-config.md +217 -0
  103. package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
  104. package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
  105. package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
  106. package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
  107. package/reference/schema/built-in-codecs/messagepack.md +508 -0
  108. package/reference/schema/built-in-codecs/thrift.md +433 -0
  109. package/reference/schema/built-in-codecs/toon.md +1078 -0
  110. package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
  111. package/reference/schema/built-in-codecs/yaml.md +552 -0
  112. package/reference/{codec.md → schema/codec.md} +11 -11
  113. package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +196 -5
  114. package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
  115. package/reference/schema/format.md +92 -0
  116. package/reference/schema/index.md +52 -0
  117. package/reference/schema/migration.md +297 -0
  118. package/reference/{modifier.md → schema/modifier.md} +58 -7
  119. package/reference/{optics.md → schema/optics.md} +2 -2
  120. package/reference/{patch.md → schema/patch.md} +1 -1
  121. package/{path-interpolator.md → reference/schema/path-interpolator.md} +167 -72
  122. package/reference/schema/reflect-transformer.md +140 -0
  123. package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
  124. package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
  125. package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
  126. package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
  127. package/reference/schema/schema-search.md +263 -0
  128. package/reference/{schema.md → schema/schema.md} +22 -2
  129. package/reference/{structural-types.md → schema/structural-types.md} +1 -1
  130. package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
  131. package/reference/smithy.md +1032 -0
  132. package/reference/sql/db-codec-deriver.md +71 -0
  133. package/reference/sql/db-codec.md +687 -0
  134. package/reference/sql/db-con.md +271 -0
  135. package/reference/sql/db-connection.md +153 -0
  136. package/reference/sql/db-param-writer.md +77 -0
  137. package/reference/sql/db-param.md +66 -0
  138. package/reference/sql/db-result-reader.md +148 -0
  139. package/reference/sql/db-tx.md +114 -0
  140. package/reference/sql/db-value.md +41 -0
  141. package/reference/sql/ddl.md +85 -0
  142. package/reference/sql/frag.md +288 -0
  143. package/reference/sql/index.md +341 -0
  144. package/reference/sql/repo.md +600 -0
  145. package/reference/sql/sql-dialect.md +73 -0
  146. package/reference/sql/sql-logger.md +62 -0
  147. package/reference/sql/sql-name-mapper.md +70 -0
  148. package/reference/sql/table-metadata.md +134 -0
  149. package/reference/sql/table.md +448 -0
  150. package/reference/sql/transactor-zio.md +399 -0
  151. package/reference/sql/transactor.md +363 -0
  152. package/reference/sql-zio.md +112 -0
  153. package/reference/streams/core/index.md +32 -0
  154. package/reference/streams/core/pipeline.md +854 -0
  155. package/reference/streams/core/sink.md +1404 -0
  156. package/reference/streams/core/stream.md +3236 -0
  157. package/reference/streams/execution-and-compatibility/async-execution.md +822 -0
  158. package/reference/streams/execution-and-compatibility/index.md +35 -0
  159. package/reference/streams/execution-and-compatibility/platform-differences.md +297 -0
  160. package/reference/streams/execution-and-compatibility/scala-2-compatibility.md +88 -0
  161. package/reference/streams/execution-and-compatibility/zero-boxing.md +393 -0
  162. package/reference/streams/index.md +726 -0
  163. package/reference/streams/primitives/index.md +30 -0
  164. package/reference/streams/primitives/reader.md +1992 -0
  165. package/reference/streams/primitives/writer.md +1201 -0
  166. package/reference/telemetry/common/any-value.md +90 -0
  167. package/reference/telemetry/common/attribute-key.md +87 -0
  168. package/reference/telemetry/common/attributes.md +118 -0
  169. package/reference/telemetry/common/index.md +39 -0
  170. package/reference/telemetry/common/instrumentation-scope.md +24 -0
  171. package/reference/telemetry/common/resource.md +34 -0
  172. package/reference/telemetry/index.md +311 -0
  173. package/reference/telemetry/logging/index.md +197 -0
  174. package/reference/telemetry/logging/log-enrichment.md +72 -0
  175. package/reference/telemetry/logging/log-formatter.md +100 -0
  176. package/reference/telemetry/logging/log-record-processor.md +56 -0
  177. package/reference/telemetry/logging/log-record.md +44 -0
  178. package/reference/telemetry/logging/log-writer.md +64 -0
  179. package/reference/telemetry/logging/logger-provider.md +142 -0
  180. package/reference/telemetry/logging/logger.md +83 -0
  181. package/reference/telemetry/logging/severity.md +62 -0
  182. package/reference/telemetry/metrics/index.md +150 -0
  183. package/reference/telemetry/metrics/instruments.md +183 -0
  184. package/reference/telemetry/metrics/labeled-instruments.md +74 -0
  185. package/reference/telemetry/metrics/meter-provider.md +76 -0
  186. package/reference/telemetry/metrics/meter.md +98 -0
  187. package/reference/telemetry/metrics/metric-data.md +57 -0
  188. package/reference/telemetry/otel/custom-exporter.md +216 -0
  189. package/reference/telemetry/otel/index.md +212 -0
  190. package/reference/telemetry/tracing/index.md +155 -0
  191. package/reference/telemetry/tracing/sampler.md +89 -0
  192. package/reference/telemetry/tracing/span-builder.md +57 -0
  193. package/reference/telemetry/tracing/span-context.md +39 -0
  194. package/reference/telemetry/tracing/span-data.md +32 -0
  195. package/reference/telemetry/tracing/span-kind.md +55 -0
  196. package/reference/telemetry/tracing/span-processor.md +53 -0
  197. package/reference/telemetry/tracing/span-status.md +47 -0
  198. package/reference/telemetry/tracing/span.md +117 -0
  199. package/reference/telemetry/tracing/tracer-provider.md +91 -0
  200. package/reference/telemetry/tracing/tracer.md +52 -0
  201. package/reference/typeid.md +5 -83
  202. package/sidebars.js +376 -43
  203. package/undocumented-report.md +528 -270
  204. package/reference/formats.md +0 -694
  205. package/reference/http-model.md +0 -1716
  206. package/reference/streams.md +0 -989
  207. package/ringbuffer.md +0 -249
  208. /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
  209. /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
  210. /package/reference/{lazy.md → schema/lazy.md} +0 -0
  211. /package/reference/{reflect.md → schema/reflect.md} +0 -0
  212. /package/reference/{registers.md → schema/registers.md} +0 -0
  213. /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
  214. /package/reference/{syntax.md → schema/syntax.md} +0 -0
  215. /package/reference/{validation.md → schema/validation.md} +0 -0
@@ -0,0 +1,146 @@
1
+ ---
2
+ id: auth-type
3
+ title: "AuthType"
4
+ ---
5
+
6
+ `AuthType` is a sealed trait that describes an HTTP authentication scheme as a first-class type parameter on `Endpoint`. Each `AuthType` variant carries an associated type `ClientRequirement` — the type of credential the client must provide — and a codec that extracts it from the request. Its definition is:
7
+
8
+ ```scala
9
+ sealed trait AuthType {
10
+ type ClientRequirement
11
+ def codec: HttpCodec[CodecKind.Request, ClientRequirement]
12
+ def unauthorizedStatus: Status
13
+ }
14
+ ```
15
+
16
+ ## Motivation
17
+
18
+ Authentication requirements are often encoded informally — a comment in the handler, a middleware convention, or a bare string header check. `AuthType` makes the auth requirement part of the endpoint's static type. A bearer-secured endpoint has type `Endpoint[..., AuthType.Bearer]`, which means:
19
+
20
+ - The `auth.codec` field is typed as `HttpCodec[CodecKind.Request, zio.http.Header.Authorization.Bearer]`, not `HttpCodec[..., String]`.
21
+ - Interpreters (server, client, OpenAPI) can inspect the auth type without stringly-typed reflection.
22
+ - Composing auth types with `|` produces a union that the compiler verifies is discriminated.
23
+
24
+ ## Built-in Variants
25
+
26
+ Each built-in variant maps to a specific HTTP authorization scheme. Use the one that matches your API's authentication model.
27
+
28
+ ### `AuthType.None`
29
+
30
+ The default auth type — no authentication required. Its `ClientRequirement` is `Unit` and its codec is `HttpCodec.Empty`:
31
+
32
+ ```scala
33
+ import zio.blocks.endpoint._
34
+ import zio.blocks.endpoint.RoutePattern._
35
+ import zio.http.Method
36
+
37
+ val publicEndpoint = Endpoint(Method.GET / "health")
38
+ ```
39
+
40
+ ### `AuthType.Basic`
41
+
42
+ HTTP Basic authentication. The `ClientRequirement` is `zio.http.Header.Authorization.Basic`:
43
+
44
+ ```scala
45
+ import zio.blocks.endpoint._
46
+ import zio.blocks.endpoint.RoutePattern._
47
+ import zio.http.Method
48
+
49
+ val basicEndpoint = Endpoint(Method.GET / "admin")
50
+ .auth(AuthType.Basic)
51
+
52
+ val codec = basicEndpoint.auth.codec
53
+ ```
54
+
55
+ ### `AuthType.Bearer`
56
+
57
+ Bearer token authentication (OAuth 2.0 / JWT). The `ClientRequirement` is `zio.http.Header.Authorization.Bearer`:
58
+
59
+ ```scala
60
+ import zio.blocks.endpoint._
61
+ import zio.blocks.endpoint.RoutePattern._
62
+ import zio.http.Method
63
+
64
+ val bearerEndpoint = Endpoint(Method.GET / "me")
65
+ .auth(AuthType.Bearer)
66
+ ```
67
+
68
+ ### `AuthType.Digest`
69
+
70
+ HTTP Digest authentication. The `ClientRequirement` is `zio.http.Header.Authorization.Digest`:
71
+
72
+ ```scala
73
+ import zio.blocks.endpoint._
74
+ import zio.blocks.endpoint.RoutePattern._
75
+ import zio.http.Method
76
+
77
+ val digestEndpoint = Endpoint(Method.GET / "secure")
78
+ .auth(AuthType.Digest)
79
+ ```
80
+
81
+ ### `AuthType.Custom`
82
+
83
+ For authentication schemes not covered by the built-in variants, `Custom` wraps any `HttpCodec[CodecKind.Request, ClientReq]`:
84
+
85
+ ```scala
86
+ import zio.blocks.endpoint._
87
+ import zio.blocks.endpoint.RoutePattern._
88
+ import zio.blocks.schema.Schema
89
+ import zio.http.Method
90
+
91
+ final case class ApiKey(value: String)
92
+
93
+ val apiKeyCodec = HttpCodec.requestHeader("X-Api-Key", Schema.string.transform[ApiKey](ApiKey(_), _.value))
94
+ val apiKeyAuth = AuthType.Custom(apiKeyCodec)
95
+ val keyEndpoint = Endpoint(Method.GET / "data").auth(apiKeyAuth)
96
+ ```
97
+
98
+ ## Composition
99
+
100
+ `AuthType` values compose in two ways: `|` builds an OR alternative that accepts either scheme, and `Scoped` attaches scope requirements to an existing auth type.
101
+
102
+ ### `AuthType#|` — OR composition
103
+
104
+ Two `AuthType` values can be combined with `|` to accept either scheme. The result is an `AuthType.Or` whose `ClientRequirement` is the union of both:
105
+
106
+ ```scala
107
+ import zio.blocks.endpoint._
108
+ import zio.blocks.endpoint.RoutePattern._
109
+ import zio.http.Method
110
+
111
+ val flexEndpoint = Endpoint(Method.GET / "resource")
112
+ .auth(AuthType.Basic | AuthType.Bearer)
113
+ ```
114
+
115
+ The `|` operator automatically computes the combined `ClientRequirement` type as a union of both requirements. The codec of the resulting `Or` is a `HttpCodec.Fallback` — it tries the left scheme first and falls back to the right.
116
+
117
+ ### `AuthType.Scoped`
118
+
119
+ To attach OAuth scope requirements to a bearer auth, wrap it in `AuthType.Scoped`:
120
+
121
+ ```scala
122
+ import zio.blocks.endpoint._
123
+ import zio.blocks.endpoint.RoutePattern._
124
+ import zio.http.Method
125
+
126
+ val scopedEndpoint = Endpoint(Method.GET / "admin")
127
+ .auth(AuthType.Scoped(AuthType.Bearer, List("admin:read", "admin:write")))
128
+ ```
129
+
130
+ `Scoped` does not change the codec — it carries the scopes as metadata for interpreters that perform scope-level authorization checks.
131
+
132
+ ## Unauthorized Status
133
+
134
+ By default, `AuthType` returns `Status.NotFound` when the client does not meet the auth requirement (to avoid leaking endpoint existence). To change this, use `Endpoint#unauthorizedStatus` or call `AuthType#withUnauthorizedStatus` directly:
135
+
136
+ ```scala
137
+ import zio.blocks.endpoint._
138
+ import zio.blocks.endpoint.RoutePattern._
139
+ import zio.http.{Method, Status}
140
+
141
+ val endpoint = Endpoint(Method.GET / "me")
142
+ .auth(AuthType.Bearer)
143
+ .unauthorizedStatus(Status.Unauthorized)
144
+ ```
145
+
146
+ `Or` composition preserves `AuthType#unauthorizedStatus` — it uses the left auth type's status.
@@ -0,0 +1,96 @@
1
+ ---
2
+ id: bulk-creation
3
+ title: "Bulk Endpoint Creation"
4
+ ---
5
+
6
+ ## Bulk endpoint creation with `endpoints { ... }`
7
+
8
+ The `endpoints` macro (Scala 3.8+ with `-experimental` for `NamedTuple`, also works on Scala 3.7 with `-experimental`) lets you define multiple `Endpoint` values in a block and access them by name on the returned `NamedTuple`. Member names are either explicit `val` names or auto-generated from the `RoutePattern.render` string (method prefix + path template). Prefix grouping via `/` (`"api" / endpoints { ... }`, `PathCodec.int("id") / endpoints { ... }`) is available via the default `import zio.blocks.endpoint.*` — no extra import is needed. All examples below assume `import zio.blocks.endpoint.*` and `scalacOptions += "-experimental"`.
9
+
10
+ String prefixes such as `"api"` are auto-converted to a literal `PathCodec[Unit]` via a `Conversion[String, PathCodec[Unit]]` provided by `zio.blocks.endpoint.*` — there is no String-specific `/` operator; constant prefixes auto-convert and use the same grouping `/` as capturing prefixes.
11
+
12
+ > **Inline-only:** prefix grouping (`prefix / endpoints { ... }`) requires an inline `endpoints { ... }` block. Binding the group to a value first (`val g = endpoints { ... }; "api" / g`) is not supported — the macro must see the block literal to compose prefixes.
13
+
14
+ ```scala
15
+ import zio.blocks.endpoint.*
16
+ import zio.blocks.endpoint.RoutePattern.*
17
+ import zio.http.Method
18
+
19
+ val api = "api" / endpoints {
20
+ val customer = Endpoint(Method.GET / "customers")
21
+ Endpoint(Method.GET / "health")
22
+ }
23
+ ```
24
+
25
+ Member access is static (zero runtime cost):
26
+
27
+ ```scala
28
+ import zio.blocks.endpoint.*
29
+ import zio.blocks.endpoint.RoutePattern.*
30
+ import zio.http.Method
31
+
32
+ val api = "api" / endpoints {
33
+ val customer = Endpoint(Method.GET / "customers")
34
+ Endpoint(Method.GET / "health")
35
+ }
36
+ val c: Endpoint[Unit, Unit, Unit, Unit, AuthType.None.type] = api.customer
37
+ val h: Endpoint[Unit, Unit, Unit, Unit, AuthType.None.type] = api.`GET /health`
38
+ ```
39
+
40
+ Auto-naming follows `RoutePattern.render` exactly:
41
+
42
+ - `GET /user/{userId}` for path variables (RFC 6570 `{var}`)
43
+ - `GET#|POST /orders` for multi-method
44
+ - `v{major}` for `~` concat segments
45
+ - `...` for trailing segments
46
+ - `.unused` renders as `{name}`
47
+
48
+ Constant-prefix nesting bakes the prefix into each child's `RoutePattern` at the description level; grouping nodes have no path themselves:
49
+
50
+ ```scala
51
+ import zio.blocks.endpoint.*
52
+ import zio.blocks.endpoint.RoutePattern.*
53
+ import zio.http.Method
54
+
55
+ val nested = "api" / endpoints {
56
+ "v1" / endpoints {
57
+ val users = Endpoint(Method.GET / "users")
58
+ }
59
+ }
60
+ val u = nested.v1.users // route.render == "GET /api/v1/users"
61
+ ```
62
+
63
+ Path-variable prefixes are implemented the same way. A capturing prefix contributes its segment to every child's path, while children keep their relative auto-names:
64
+
65
+ ```scala
66
+ import zio.blocks.endpoint.*
67
+ import zio.blocks.endpoint.RoutePattern.*
68
+ import zio.http.Method
69
+
70
+ val byId = PathCodec.int("id") / endpoints {
71
+ val get = Endpoint(Method.GET / "orders")
72
+ Endpoint(Method.DELETE / "orders") // auto-named `DELETE /orders`
73
+ }
74
+
75
+ val getOrder: Endpoint[Int, Unit, Unit, Unit, AuthType.None.type] = byId.get
76
+ val delOrder = byId.`DELETE /orders`
77
+ ```
78
+
79
+ Both children carry the captured segment: `byId.get.route.render == "GET /{id}/orders"` and the auto-named member renders `"DELETE /{id}/orders"`. Static types are preserved — `byId.get` is an `Endpoint[Int, Unit, Unit, Unit, AuthType.None.type]`, so the captured `id` will be delivered to handlers when routes are created on the zio-http side. A child with its own path variables composes positionally: under `int("id")`, `Endpoint(Method.GET / "orders" / PathCodec.int("orderId"))` renders as `GET /{id}/orders/{orderId}` and carries `(Int, Int)`:
80
+
81
+ ```scala
82
+ import zio.blocks.endpoint.*
83
+ import zio.blocks.endpoint.RoutePattern.*
84
+ import zio.http.Method
85
+
86
+ val ordersById = PathCodec.int("id") / endpoints {
87
+ val o = Endpoint(Method.GET / "orders" / PathCodec.int("orderId"))
88
+ }
89
+
90
+ val lookup: Endpoint[(Int, Int), Unit, Unit, Unit, AuthType.None.type] = ordersById.o
91
+ // lookup.route.render == "GET /{id}/orders/{orderId}"
92
+ ```
93
+
94
+ Variable prefixes should be bound to an explicit `val` — the val names the subgroup whose members you access through it (`byId.get`, `ordersById.o`). Constant-prefix and capturing-prefix subgroups can be freely nested inside each other: `"api" / endpoints { PathCodec.int("id") / endpoints { ... } }` composes both prefixes into every leaf route at compile time.
95
+
96
+ The returned type is a Scala 3 `NamedTuple` — static member access, erased at runtime. The DSL is Scala 3 only (3.7+ with `-experimental` for named tuples). All examples above compile against the `endpoint` module on Scala 3.8.3 with `scalacOptions += "-experimental"`.
@@ -0,0 +1,297 @@
1
+ ---
2
+ id: endpoint
3
+ title: "Endpoint"
4
+ ---
5
+
6
+ `Endpoint[PathInput, Input, Err, Output, Auth]` is the top-level descriptor for an HTTP endpoint. It holds a typed route, three independent codec channels (request input, error output, success output), an authentication type, and documentation metadata. `Endpoint` is pure data — it carries no server or client logic and imposes no effect type. Its full shape is:
7
+
8
+ ```scala
9
+ final case class Endpoint[PathInput, Input, Err, Output, Auth <: AuthType](
10
+ route: RoutePattern[PathInput],
11
+ input: HttpCodec[CodecKind.Request, Input],
12
+ error: HttpCodec[CodecKind.Response, Err],
13
+ output: HttpCodec[CodecKind.Response, Output],
14
+ auth: Auth,
15
+ doc: Doc
16
+ )
17
+ ```
18
+
19
+ ## Motivation
20
+
21
+ An endpoint descriptor separates the **shape** of an HTTP surface from its **execution**. A single `Endpoint` value can be interpreted by a server to generate routes, by a client generator to produce typed API calls, or by an OpenAPI renderer to produce specification documents. This means the endpoint definition is the single source of truth — change it once and every interpreter updates.
22
+
23
+ The five type parameters track everything the compiler needs to enforce consistency across the whole stack:
24
+
25
+ | Parameter | Meaning |
26
+ |-------------|------------------------------------------------------------|
27
+ | `PathInput` | Type of values extracted from path segments |
28
+ | `Input` | Aggregate type of all request inputs (query, header, body) |
29
+ | `Err` | Aggregate type of all error response shapes |
30
+ | `Output` | Aggregate type of all success response shapes |
31
+ | `Auth` | Authentication scheme, carries the client requirement |
32
+
33
+ ## Construction
34
+
35
+ We create an `Endpoint` from a `RoutePattern` using `Endpoint.apply`:
36
+
37
+ ```scala
38
+ import zio.blocks.endpoint._
39
+ import zio.blocks.endpoint.RoutePattern._
40
+ import zio.http.Method
41
+
42
+ val ep = Endpoint(Method.GET / "users" / PathCodec.int("id"))
43
+ ```
44
+
45
+ The route can also be built from a separate `RoutePattern` value:
46
+
47
+ ```scala
48
+ import zio.blocks.endpoint._
49
+ import zio.blocks.endpoint.RoutePattern._
50
+ import zio.http.Method
51
+
52
+ val route = Method.POST / "orders" / PathCodec.uuid("orderId")
53
+ val ep = Endpoint(route)
54
+ ```
55
+
56
+ The initial `Endpoint` starts with `Unit` for all three codec channels and `AuthType.None` for auth, so further builder calls always widen the types additively.
57
+
58
+ ## Request Input Builders
59
+
60
+ Every `Endpoint#in`, `Endpoint#query`, and `Endpoint#header` call adds another input component to the endpoint, widening the `Input` type parameter.
61
+
62
+ ### Body input
63
+
64
+ To add a request body typed by a `Schema`, use `Endpoint#in`:
65
+
66
+ ```scala
67
+ import zio.blocks.endpoint._
68
+ import zio.blocks.endpoint.RoutePattern._
69
+ import zio.blocks.schema.Schema
70
+ import zio.http.Method
71
+
72
+ val ep = Endpoint(Method.POST / "users")
73
+ .in(Schema.string)
74
+ ```
75
+
76
+ To specify the content type explicitly, pass a `MediaType` as well:
77
+
78
+ ```scala
79
+ import zio.blocks.endpoint._
80
+ import zio.blocks.endpoint.RoutePattern._
81
+ import zio.blocks.mediatype.MediaTypes
82
+ import zio.blocks.schema.Schema
83
+ import zio.http.Method
84
+
85
+ val ep = Endpoint(Method.POST / "users")
86
+ .in(MediaTypes.application.`json`, Schema.string)
87
+ ```
88
+
89
+ To add a raw `HttpCodec.Body` node directly, use `Endpoint#in`:
90
+
91
+ ```scala
92
+ import zio.blocks.endpoint._
93
+ import zio.blocks.endpoint.RoutePattern._
94
+ import zio.blocks.schema.Schema
95
+ import zio.http.Method
96
+
97
+ val ep = Endpoint(Method.POST / "users")
98
+ .in(HttpCodec.requestBody(Schema.string))
99
+ ```
100
+
101
+ ### Query parameters
102
+
103
+ To add a query parameter by name and schema, use `Endpoint#query`:
104
+
105
+ ```scala
106
+ import zio.blocks.endpoint._
107
+ import zio.blocks.endpoint.RoutePattern._
108
+ import zio.blocks.schema.Schema
109
+ import zio.http.Method
110
+
111
+ val ep = Endpoint(Method.GET / "users")
112
+ .query("page", Schema.int)
113
+ .query("limit", Schema.int)
114
+ ```
115
+
116
+ To add a pre-built `HttpCodec.Query` node, use `Endpoint#query`:
117
+
118
+ ```scala
119
+ import zio.blocks.endpoint._
120
+ import zio.blocks.endpoint.RoutePattern._
121
+ import zio.blocks.schema.Schema
122
+ import zio.http.Method
123
+
124
+ val pageCodec = HttpCodec.query("page", Schema.int)
125
+ val ep = Endpoint(Method.GET / "users").query(pageCodec)
126
+ ```
127
+
128
+ ### Request headers
129
+
130
+ To add a request header by name and schema, use `Endpoint#header`:
131
+
132
+ ```scala
133
+ import zio.blocks.endpoint._
134
+ import zio.blocks.endpoint.RoutePattern._
135
+ import zio.blocks.schema.Schema
136
+ import zio.http.Method
137
+
138
+ val ep = Endpoint(Method.GET / "users")
139
+ .header("X-Trace-Id", Schema.string)
140
+ ```
141
+
142
+ To add a pre-built `HttpCodec.Header` node, use `Endpoint#header`:
143
+
144
+ ```scala
145
+ import zio.blocks.endpoint._
146
+ import zio.blocks.endpoint.RoutePattern._
147
+ import zio.blocks.schema.Schema
148
+ import zio.http.Method
149
+
150
+ val traceCodec = HttpCodec.requestHeader("X-Trace-Id", Schema.string)
151
+ val ep = Endpoint(Method.GET / "users").header(traceCodec)
152
+ ```
153
+
154
+ ## Success Output Builders
155
+
156
+ Every `Endpoint#out` and `Endpoint#outHeader` call adds a success response alternative or header component, widening `Output`.
157
+
158
+ ### Response body
159
+
160
+ To add a 200 OK response body, use `Endpoint#out`:
161
+
162
+ ```scala
163
+ import zio.blocks.endpoint._
164
+ import zio.blocks.endpoint.RoutePattern._
165
+ import zio.blocks.schema.Schema
166
+ import zio.http.Method
167
+
168
+ val ep = Endpoint(Method.GET / "users")
169
+ .out(Schema.string)
170
+ ```
171
+
172
+ To specify a non-200 status code, use `Endpoint#out` with a `Status`:
173
+
174
+ ```scala
175
+ import zio.blocks.endpoint._
176
+ import zio.blocks.endpoint.RoutePattern._
177
+ import zio.blocks.schema.Schema
178
+ import zio.http.{Method, Status}
179
+
180
+ val ep = Endpoint(Method.POST / "users")
181
+ .out(Status.Created, Schema.int)
182
+ ```
183
+
184
+ To add content-type negotiation, pass a `MediaType`:
185
+
186
+ ```scala
187
+ import zio.blocks.endpoint._
188
+ import zio.blocks.endpoint.RoutePattern._
189
+ import zio.blocks.mediatype.MediaTypes
190
+ import zio.blocks.schema.Schema
191
+ import zio.http.{Method, Status}
192
+
193
+ val ep = Endpoint(Method.GET / "users")
194
+ .out(MediaTypes.application.`json`, Schema.string)
195
+ .out(Status.Created, MediaTypes.text.`plain`, Schema.int)
196
+ ```
197
+
198
+ Multiple `Endpoint#out` calls produce alternatives. The output type widens from `Unit` to the first schema type, then to a nested `Either` for each additional alternative.
199
+
200
+ ### Response headers
201
+
202
+ To add a typed response header, use `Endpoint#outHeader`:
203
+
204
+ ```scala
205
+ import zio.blocks.endpoint._
206
+ import zio.blocks.endpoint.RoutePattern._
207
+ import zio.blocks.schema.Schema
208
+ import zio.http.Method
209
+
210
+ val ep = Endpoint(Method.GET / "users")
211
+ .out(Schema.string)
212
+ .outHeader("X-Total-Count", Schema.int)
213
+ ```
214
+
215
+ ## Error Output Builders
216
+
217
+ Error channels work like success channels but populate the `Err` type parameter. Two variants exist: `Endpoint#outError` (cross-version) and `Endpoint#orOutError` (Scala 3 unions).
218
+
219
+ ### `Endpoint#outError` — cross-version additive errors
220
+
221
+ To add an error response with a status code and body schema, use `Endpoint#outError`:
222
+
223
+ ```scala
224
+ import zio.blocks.endpoint._
225
+ import zio.blocks.endpoint.RoutePattern._
226
+ import zio.blocks.schema.Schema
227
+ import zio.http.{Method, Status}
228
+
229
+ val ep = Endpoint(Method.GET / "users")
230
+ .out(Schema.string)
231
+ .outError(Status.NotFound, Schema.string)
232
+ .outError(Status.BadRequest, Schema.string)
233
+ ```
234
+
235
+ Each `Endpoint#outError` call widens `Err` by one nested `Either` layer.
236
+
237
+ ### `Endpoint#orOutError` — Scala 3 union errors
238
+
239
+ On Scala 3, `Endpoint#orOutError` accumulates error types as a native union type instead of nested `Either`s. The first call replaces the initial `Unit` error outright; subsequent calls build a `Fallback` codec backed by `Unions` derivation:
240
+
241
+ ```scala
242
+ import zio.blocks.endpoint._
243
+ import zio.blocks.endpoint.RoutePattern._
244
+ import zio.blocks.schema.Schema
245
+ import zio.http.{Method, Status}
246
+
247
+ val ep = Endpoint(Method.GET / "users")
248
+ .orOutError(Status.NotFound, Schema.string)
249
+ .orOutError(Status.Conflict, Schema.int)
250
+
251
+ val typed: Endpoint[Unit, Unit, String | Int, Unit, AuthType.None.type] = ep
252
+ ```
253
+
254
+ The compiler rejects overlapping union members — two `Endpoint#orOutError` calls both using `Schema.string` produce a compile error because `String | String` is not a valid discriminated union.
255
+
256
+ ## Authentication
257
+
258
+ To attach an authentication scheme, use `Endpoint#auth`:
259
+
260
+ ```scala
261
+ import zio.blocks.endpoint._
262
+ import zio.blocks.endpoint.RoutePattern._
263
+ import zio.http.Method
264
+
265
+ val secured = Endpoint(Method.GET / "me")
266
+ .auth(AuthType.Bearer)
267
+ ```
268
+
269
+ The `Auth` type parameter carries the `ClientRequirement` associated type, so a bearer-secured endpoint exposes `auth.codec` typed as `HttpCodec[CodecKind.Request, zio.http.Header.Authorization.Bearer]`. See [AuthType](./auth-type.md) for all variants.
270
+
271
+ To override the HTTP status the server sends when the client does not meet the auth requirement, use `Endpoint#unauthorizedStatus`:
272
+
273
+ ```scala
274
+ import zio.blocks.endpoint._
275
+ import zio.blocks.endpoint.RoutePattern._
276
+ import zio.http.{Method, Status}
277
+
278
+ val secured = Endpoint(Method.GET / "me")
279
+ .auth(AuthType.Bearer)
280
+ .unauthorizedStatus(Status.Unauthorized)
281
+ ```
282
+
283
+ ## Documentation
284
+
285
+ To attach a `Doc` value to the endpoint as a whole, use `Endpoint#doc`:
286
+
287
+ ```scala
288
+ import zio.blocks.docs.Doc
289
+ import zio.blocks.endpoint._
290
+ import zio.blocks.endpoint.RoutePattern._
291
+ import zio.http.Method
292
+
293
+ val ep = Endpoint(Method.GET / "users")
294
+ .doc(Doc.empty)
295
+ ```
296
+
297
+ Documentation attached here flows through to OpenAPI generation and any other documentation interpreters.